DB Object중 하나(테이블, 시퀀스, 제약사항, 뷰) -> 데이터 베이스에 영구 저장
가상 테이블, 뷰 테이블
일종의 테이블의 복사본
뷰는 테이블처럼 취급한다.
자주 사용하는 select의 결과를 저장하는 객체(★★★★)
테이블을 직접 사용하는 것에 비해 간편함(구문 단축)
뷰는 읽기 전용이다.(★★★)
뷰는 select의 결과를 저장하는 객체(X) -> select문을 저장하는 객체(O)(★★★★★★)
create view 뷰이름
as
select문
-- 뷰 생성
-- ORA-00955: name is already used by an existing object 동일한 이름을 가진 객체를 만들 수 없다.
create view vwInsa
as
select * from tblInsa;
select * from tblinsa; -- 테이블보기
select * from vwinsa; -- 뷰보기
select * from tblinsa where buseo = '기획부';
select * from vwinsa where buseo = '개발부';
drop view vwinsa;
-- create or : 없으면 만들고, 있으면 수정(대체, 기존것을 없애고 새로 만듦)
create or replace view vwinsa
as
select * from tblinsa where buseo = '기획부';
-- vwInsa : 기획부 직원 테이블
select * from vwinsa;
create or replace view vwInsaMaleSeoul
as
select * from tblinsa where substr(ssn, 8,1) = '1' and city = '서울';
select * from vwInsaMaleSeoul;
-- system계정으로 변경 후 실행하면 에러남.
-- ORA-00942: table or view does not exist
-- 관리자 계정은 모든 다른 계정의 자원을 접근할 수 있음.(앞에 소유주를 써주면 된다.)
select * from hr.tblinsa;
select * from hr.vwInsaMaleSeoul;
create or replace view vwvideo
as
select
m.name as "회원명",
v.name as "비디오제목",
r.rentdate as "대여날짜",
case
when r.retdate is null then '반납안함'
when r.retdate is not null then '반납완료'
end as "반납상태"
from tblgenre g
inner join tblvideo v
on g.seq = v.genre
inner join tblrent r
on v.seq = r.video
inner join tblmember m
on m.seq = r.member;
select * from vwvideo;
-- 불가능한 행동(복합뷰)
-- insert into vwvideo(회원명, 비디오제목, 대여날짜, 반납상태) values ('홍길동', '해리포터','2021-05-21', null);
-- delete from vwvideo where 조건;
-- 서울 직원 뷰
-- 홍길동 -> 서울
create or replace view vwSeoul
as
select * from tblinsa where city = '서울';
select * from vwSeoul;
commit;
rollback;
select * from tblInsa;
-- 홍길동 -> 제주
update tblInsa set city = '제주' where num = 1001;
-- 홍길동이 없음... -> 테이블을 건드렸더니 뷰에도 영향을 미침.
select * from vwSeoul;
-- 서울 직원 삭제
delete from tblInsa where city = '서울';
-- 서울 직원이 다 삭제됨..
select * from vwSeoul;
-- 뷰는 select문을 저장하는 객체이다!!!
commit;
rollback;
create or replace view vwMen
as
select * from tblMen;
-- 1. select
select * from vwMen;
-- 2. insert
insert into (name, age, height, weight, couple) values ('테스트', 20,175, 65, null);
-- 3. update
update vwMen set age = 25 where name = '테스트';
-- 4. delete
delete from vwMen where name = '테스트';
-- 이름만 가지고 insert, update, delete 쓸 수 있는 뷰(복합뷰,단순뷰)인지 아닌지 혼동이 된다.
-- vwInsa
-- vwInsaSeoul
-- vwMen
-- vwContry
-- 인라인 뷰, Inline view
create or replace view vwSeoul
as
select * from tblInsa where city = '서울';
select * from vwSeoul; -- 재사용 가능
-- 서브쿼리를 from절에 사용 == 인라인뷰
select * from (select * from tblInsa where city = '서울'); -- 1회성
select * from tblMen;
select * from tblWomen;
select * from tblMen m
inner join tblWomen w
on m.couple = w.name;
-- 데이터베이스 연산
-- union
-- 1. 컬럼의 개수가 일치해야한다.
-- 2. 컬럼의 타입이 일치해야한다.
-- 1,2가 불일치하면 union 실패
select * from tblMen
union -- (+)
select * from tblWomen;
-- 유니온의 성질
create table tblUnionA(
color varchar2(30) not null
);
create table tblUnionB(
color varchar2(30) not null
);
insert into tblUnionA values ('red');
insert into tblUnionA values ('yellow');
insert into tblUnionA values ('blue');
insert into tblUnionA values ('black');
insert into tblUnionA values ('white');
insert into tblUnionB values ('orange');
insert into tblUnionB values ('green');
insert into tblUnionB values ('skyblue');
insert into tblUnionB values ('yellow');
insert into tblUnionB values ('red');
-- union : 두 테이블을 합쳤을 때 중복되는 행을 자동으로 제거 *****
select * from tblUnionA
union
select * from tblUnionB;
-- union all : 두 테이블을 합쳤을 때 중복되는 행을 그대로 포함
select * from tblUnionA
union all
select * from tblUnionB;
-- intersect : 두 테이블을 합쳤을 때 중복되는 행만 포함(교집합)
select * from tblUnionA
intersect
select * from tblUnionB;
-- minus : A - B
select * from tblUnionA
minus
select * from tblUnionB;
-- 에러 : 와일드카드(*)와 다른 컬럼(표현식 등)은 목록으로 연결될 수 없다.
-- select *, sysdate from tblcountry;
select c.*, sysdate from tblcountry c;
-- 질문의 조건에 1행이 포함되면 결과O, 포함안되면 결과X
select c.*, rownum from tblcountry c;
select c.*, rownum from tblcountry c where rownum = 1;
select c.*, rownum from tblcountry c where rownum <= 5;
select c.*, rownum from tblcountry c where rownum = 5; -- x
select c.*, rownum from tblcountry c where rownum >= 3 and rownum <= 7; -- x
-- 급여를 많이 받는 순으로 1~10등까지 가져오기
select -- 2.
name,
basicpay,
rownum
from tblInsa -- 1. 60명 + rownum할당
order by basicpay desc; -- 3. rownum 이미 1번에 할당이 끝났다.
-- 인라인 뷰(from절 서브쿼리)
select name, basicpay, rnum, rownum from (select name, basicpay, rownum as rnum from tblInsa order by basicpay desc);
select name, basicpay, rownum from (select name, basicpay from tblInsa order by basicpay desc) where rownum <= 10;
select name, basicpay, rownum from (select name, basicpay from tblInsa order by basicpay desc) where rownum = 1; -- 급여순위 1등
-- select name, basicpay, rownum from (select name, basicpay from tblInsa order by basicpay desc) where rownum >=3 and rownum <= 5;
-- 급여 순위 3~5등
-- rnum : 가운데 쿼리의 rownum : 정적인 번호
-- rownum : 바깥쪽 쿼리의 rownum : 동적인 번호
select name, basicpay, rnum from (select name, basicpay, rownum as rnum from (select name, basicpay from tblInsa order by basicpay desc))
where rnum between 3 and 5;
-- basicpay + sudang -> 급여 순위
-- 정리. 이 2가지 경우만 이해하면 끝!!!
-- Case A.
select name, salary, rownum from (select name, basicpay + sudang as salary from tblInsa order by basicpay + sudang desc)
where rownum <= 3;
-- Case B.
select * from (select name, salary, rownum as rnum from (select name, basicpay + sudang as salary from tblInsa order by basicpay + sudang desc))
where rnum >= 5 and rnum <= 10;
-- 지역별(hometown) 거주자가 몇명? -> 지역별 거주자가 많은 순위 1~3
select hometown, cnt, rownum from (select
hometown,
count(*) as cnt
-- rownum -> 개인정보
from tbladdressbook
group by hometown
order by count(*) desc)
where rownum <= 3;
-- 5위
select * from (select hometown, cnt, rownum as rnum from (select
hometown,
count(*) as cnt
-- rownum -> 개인정보
from tbladdressbook
group by hometown
order by count(*) desc))
where rnum = 5;
-- tblAddressBook. 직업별 인원수 -> 순위 1~10등, 11~20등
select * from (select a.*, rownum as rnum from (select job, count(*) as cnt from tblAddressBook group by job order by count(*) desc) a);
select * from (select a.*, rownum as rnum from (select job, count(*) as cnt from tblAddressBook group by job order by count(*) desc) a)
where rnum between 1 and 10;
select * from (select a.*, rownum as rnum from (select job, count(*) as cnt from tblAddressBook group by job order by count(*) desc) a)
where rnum between 11 and 20;
컴퓨터
- 본체
- 메인보드
- 그래픽카드
- 랜카드
- CPU
- 메모리
- 모니터
- 보호필름
- 프린터
- 잉크카트리지
- A4용지
create table tblComputer (
seq number primary key, -- 식별자(PK)
name varchar2(50) not null, -- 요소명
qty number not null, -- 수량
pseq number null references tblComputer -- 부모 부품(FK)
);
insert into tblComputer values (1, '컴퓨터', 1, null); -- 루트(root)
insert into tblComputer values (2, '본체', 1, 1);
insert into tblComputer values (3, '모니터', 1, 1);
insert into tblComputer values (4, '프린터', 1, 1);
insert into tblComputer values (5, '메인보드', 1, 2);
insert into tblComputer values (6, '그래픽카드', 1, 2);
insert into tblComputer values (7, '랜카드', 1, 2);
insert into tblComputer values (8, 'CPU', 1, 2);
insert into tblComputer values (9, '메모리', 1, 2);
insert into tblComputer values (10, '보호필름', 1, 3);
insert into tblComputer values (11, '잉크카트리지', 1, 4);
insert into tblComputer values (12, 'A4용지', 100, 4);
select * from tblComputer;
-- 셀프조인: 부품 + 부모부품
select
c1.name as "부품",
c2.name as "부모부품"
from tblComputer c1
inner join tblComputer c2
on c1.pseq = c2.seq;
select
c1.name as "부품",
c2.name as "부모부품"
from tblComputer c1
left outer join tblComputer c2
on c1.pseq = c2.seq;
/*
계층형 쿼리
- start with절 + connect by절
- 계층형 쿼리에서만 사용 가능한 의사 컬럼을 제공
- prior : 의사컬럼. 가상 부모 레코드
- level : 의사컬럼. N세대, (누가 상위요소인지 하위요소인지 알 수 있음, 계층구조)
- start with : 최상위 요소를 어떤 걸로 시작할 지 정함
*/
select
lpad(' ', (level -1) * 5) || name,
prior name,
level
from tblComputer
-- start with seq = 1
-- start with seq = (select seq from tblComputer where name = '컴퓨터')
start with pseq is null
connect by prior seq = pseq; -- 부모 자식을 연결시켜주는 연결고리
select
lpad(' ',(level - 1) * 2) || name as 직원명,
-- prior name as 상사명
department
from tblself
start with super is null
connect by super = prior seq;
-- prior : 부모 레코드
-- connect_by_root : 최상위 레코드
select
lpad(' ', (level -1) * 5) || name,
prior name,
level,
connect_by_root name as "루트부품명",
connect_by_isleaf as "리프노드", -- 최말단 노드인지 알려줌
sys_connect_by_path(name,'->')
from tblComputer
start with pseq is null
connect by prior seq = pseq
-- order by name asc -- 일반 정렬 사용 불가
order siblings by name asc; -- 형제끼리만 정렬