직원 정보 테이블
-- 테이블 생성
create table tblStaff(
seq number primary key, -- 직원번호(PK)
name varchar2(30) not null, -- 직원명
salary number not null, -- 급여
address varchar2(300) not null, -- 거주지
project varchar2(300) null -- 담당프로젝트
);
insert into tblStaff(seq, name, salary, address, project) values (1,'홍길동', 300, '서울시', '홍콩수출');
insert into tblStaff(seq, name, salary, address, project) values (2,'아무개', 250, '부산시', 'tv광고');
insert into tblStaff(seq, name, salary, address, project) values (3,'하하하', 280, '대전시', '매출분석');
1명의 직원이 2개 이상의 프로젝트를 담당했을때
=> 결론 : 둘 다 좋은 방식이 아님 -> 테이블 설계의 miss...
-- 2번째 프로젝트
-- 홍길동 + 프로젝트 1건 추가(고객관리)
insert into tblStaff(seq, name, salary, address, project) values (4,'홍길동', 300, '서울시', '고객관리');
-- 호호호 + 2개 프로젝트
insert into tblStaff(seq, name, salary, address, project) values (5,'호호호', 270, '의정부시', '홍콩수출,고객관리');
-- 홍길동 급여 수정
update tblStaff set salary = 310 where seq = 1; -- 홍길동은 1번 4번에 있음... -> 1번 홍길동만 급여가 310으로 바뀜 -> 무결성이 깨짐
-- 3번째 프로젝트
-- 홍길동 + 프로젝트 추가
insert into tblStaff(seq, name, salary, address, project) values (6,'홍길동', 300, '서울시', '반품처리');
-- 호호호 + 프로젝트 추가
update tblStaff set project = project || ', 반품처리' where seq = 5;
-- 홍길동 고객관리 -> 담당 해체
delete from tblstaff where seq = 4;
-- 호호호 고객관리 -> 담당 해제
update tblStaff set project = replace(project, '고객관리,', '') where seq = 5; -- 특정 프로젝트만 지정해서 수정하기 어렵다.
select * from tblstaff;
drop table tblstaff;
drop table tblProject;
-- (부모테이블)
create table tblStaff(
seq number primary key, -- 직원번호(PK)
name varchar2(30) not null, -- 직원명
salary number not null, -- 급여
address varchar2(300) not null -- 거주지
);
create table tblProject(
seq number primary key, -- 프로젝트 번호(PK)
project varchar2(300) null, -- 담당프로젝트
staff_seq number not null -- 직원번호
);
insert into tblStaff(seq, name, salary, address) values (1,'홍길동', 300, '서울시');
insert into tblStaff(seq, name, salary, address) values (2,'아무개', 250, '부산시');
insert into tblStaff(seq, name, salary, address) values (3,'하하하', 280, '대전시');
insert into tblStaff(seq, name, salary, address) values (5,'후후후', 250, '서울시');
insert into tblProject(seq, project, staff_seq) values (1, '홍콩수출', 1);
insert into tblProject(seq, project, staff_seq) values (2, 'Tv광고', 2);
insert into tblProject(seq, project, staff_seq) values (3, '매출분석', 3);
-- 홍길동 + 프로젝트 1개 추가
insert into tblProject(seq, project, staff_seq) values (4, '노조협상', 1);
-- 홍길동 + 프로젝트 1개 해제
delete from tblProject where seq = 1;
select * from tblstaff;
select * from tblProject;
-- 위의 2개의 테이블의 문제점!!
-- A. 신입 사원 입사 -> 신규 프로젝트 담당
-- A.1 신입 사원 추가(o)
insert into tblStaff(seq, name, salary, address) values (4,'호호호', 200, '서울시');
-- A.2 신규 프로젝트 추가(o)
insert into tblProject(seq, project, staff_seq) values (5, '자재매입', 4);
-- A.3 신규 프로젝트 추가(x)
insert into tblProject(seq, project, staff_seq) values (6, '고객유치', 5); -- 없는 직원(데이터)번호 사용 -> 있는 직원번호인지 아닌지 체크 해야함!!!
-- B. '홍길동'퇴사
-- B.1 '홍길동'삭제(x)
delete from tblStaff where seq = 1; -- 존재하지 않는 직원이 프로젝트를 담당하게됨..
-- B.2 '홍길동'의 모든 업무 > 위임(업무 인수인계)
update tblProject set staff_seq = 2 where staff_seq = 1;
-- B.3 '홍길동' 삭제(o)
delete from tblStaff where seq = 1;
-- (부모테이블)
create table tblStaff(
seq number primary key, -- 직원번호(PK)
name varchar2(30) not null, -- 직원명
salary number not null, -- 급여
address varchar2(300) not null -- 거주지
);
-- 수정★★★★
-- (자식테이블)
create table tblProject(
seq number primary key, -- 프로젝트 번호(PK)
project varchar2(300) null, -- 담당프로젝트
-- staff_seq에 들어가는 번호는 tblSatff(seq)를 참조한다.
staff_seq number not null references tblStaff(seq) -- 직원번호(FK, Foreign Key, 외래키, 참조키)
);
-- tblStaff - tblProject
-- PK(부모키) - FK(자식키)
-- 부모 - 자식
-- 부모테이블 - 자식 테이블
insert into tblStaff(seq, name, salary, address) values (1,'홍길동', 300, '서울시');
insert into tblStaff(seq, name, salary, address) values (2,'아무개', 250, '부산시');
insert into tblStaff(seq, name, salary, address) values (3,'하하하', 280, '대전시');
insert into tblProject(seq, project, staff_seq) values (1, '홍콩수출', 1);
insert into tblProject(seq, project, staff_seq) values (2, 'Tv광고', 2);
insert into tblProject(seq, project, staff_seq) values (3, '매출분석', 3);
-- A. 신입 사원 입사 -> 신규 프로젝트 담당
-- A.1 신입 사원 추가(o)
insert into tblStaff(seq, name, salary, address) values (4,'호호호', 200, '서울시');
-- A.2 신규 프로젝트 추가(o)
insert into tblProject(seq, project, staff_seq) values (5, '자재매입', 4);
-- A.3 신규 프로젝트 추가(x)
-- ORA-02291: integrity constraint (HR.SYS_C007173) violated - parent key not found
-- 에러 : 무결성 제약조건이 위배되었습니다.(부모키가 없습니다.)
-- insert into tblProject(seq, project, staff_seq) values (6, '고객유치', 5); -- 존재하지 않는 직원번호를 사전에 막음
-- B. '홍길동'퇴사
-- B.1 '홍길동'삭제(x)
-- ORA-02292: integrity constraint (HR.SYS_C007173) violated - child record found
-- 무결성 제약조건이 위배되었습니다.(자식 레코드가 발견되었습니다.)
-- 홍길동을 참조하고 있는 데이터가 있기 때문에 홍길동을 삭제하면 참조데이터가 이상해질 수 있기 때문에 에러가 난다.
delete from tblStaff where seq = 1;
-- B.2 '홍길동'의 모든 업무 > 위임(업무 인수인계)
-- 홍길동이 업무를 위임하면 참조하는 데이터가 없기 때문에 위임을 해야 삭제 가능.
update tblProject set staff_seq = 2 where staff_seq = 1;
-- B.3 '홍길동' 삭제(o)
delete from tblStaff where seq = 1;
-- tblcustomer이 자식 테이블이라고 가정했을때
-- 고객 <-> 판매
-- 1. 고객이 회원가입 > 신규회원은 판매내역이 없음 > sseq 비워둔채 가입
-- 2. 구매 > insert(tblSales) + update(tblCustomer) 판매내역 갱신
-- 3. 또 다른 물건 구매 > insert(tblSales) + update(tblCustomer) -> 이미 1이 들어있음 -> "1,2" -> 데이터 관리 어려움..
-- tblsales가 자식 테이블이라고 가정했을때
-- 1. 고객이 회원가입 -> 비워두는 컬럼없음
-- 2. 구매 > insert(tblSales)
-- 3. 또 다른 물건 구매 > insert(tblSales)
-- 고객 테이블 (부모 테이블)
create table tblcustomer(
seq number primary key, -- 고객번호(PK)
name varchar2(30) not null, -- 고객명
tel varchar2(15) not null, -- 연락처
address varchar2(100) not null -- 주소
-- sseq number null reference tblSales(seq) -- 참조키(판매내역번호) -> 신규회원은 이용내역이 없음 -> null
);
-- 판매 내역 테이블 (자식 테이블)
create table tblsales(
seq number primary key, -- 판매번호(PK)
item varchar2(50) not null, -- 제품명
qty number not null, -- 수량
regdate date default sysdate not null, -- 판매날짜
-- 두테이블을 관계를 맺을때는 자식 테이블이 부모 테이블의 primary key를 참조한다.(유일하게 구별할 수 있는 식별자)★★★
cseq number not null references tblCustomer(seq) -- 고객번호(FK) -> 누가 사갔는지 알아야하기 때문에 not null
);
select * from tblcustomer;
select * from tblsales;
-- 비디오 대여점
drop table tblGenre;
drop table tblVideo;
drop table tblMember;
drop table tblRent;
-- 장르 테이블
create table tblGenre (
seq number primary key, -- 장르번호(PK)
name varchar2(30) not null, -- 장르명
price number not null, -- 대여가격 (장르별로 가격이 다름)
period number not null -- 대여기간(일) (장르별로 대여기간이 다름)
);
-- 비디오 테이블
create table tblVideo (
seq number primary key, -- 비디오번호(PK)
name varchar2(100) not null, -- 제목
qty number not null, -- 보유 수량
company varchar2(50) null, -- 제작사
director varchar2(50) null, -- 감독
major varchar2(50) null, -- 주연배우
genre number not null references tblGenre(seq) -- 장르(FK)
);
-- 고객 테이블
create table tblMember (
seq number primary key, -- 회원번호(PK)
name varchar2(30) not null, -- 회원명
grade number(1) not null, -- 회원등급(1,2,3)
byear number(4) not null, -- 생년
tel varchar2(15) not null, -- 연락처
address varchar2(300) not null, -- 주소
money number not null -- 예치금
);
-- 대여 테이블
create table tblRent (
seq number primary key, -- 대여번호(PK)
member number not null references tblMember(seq), -- 회원번호(FK)
video number not null references tblVideo(seq), -- 비디오번호(FK)
rentdate date default sysdate not null, -- 대여시각
retdate date null, -- 반납시각 -> 언제 반납하는지 알 수 없기때문에 null
remark varchar2(500) null -- 비고
);
-- 시퀀스 생성
create sequence genreSeq;
create sequence videoSeq;
create sequence memberSeq;
create sequence rentSeq;
-- 시퀀스 삭제
drop sequence genreSeq;
drop sequence videoSeq;
drop sequence memberSeq;
drop sequence rentSeq;
-- 테이블 확인
select * from tblGenre; -- 6개
select * from tblVideo; -- 11개
select * from tblMember; -- 10개
select * from tblRent; -- 6개
-- 테이블 내용 삭제
delete from tblGenre;
delete from tblVideo;
delete from tblMember;
delete from tblRent;
select * from tblcustomer; -- 3건
select * from tblSales; -- 9건
-- tblCustomer + tblSales
select * from tblCustomer cross join tblSales; -- 27건, --> ANSI SQL
select * from tblCustomer, tblSales; --> Oracle
-- 개발자가 테스트 용도의 큰 데이터가 필요한 경우에 사용 - 더미 데이터
select * from tbladdressbook cross join tblComedian cross join tblCountry; -- 여러개 조인
select * from tblcustomer;
select * from tblSales;
-- 고객정보와 판매내역을 동시에 가져오기
select * from tblCustomer
inner join tblSales
-- tblCustomer.seq과 tblSales.cseq에서 똑같은 값만 가져와라
on tblCustomer.seq = tblSales.cseq; -- 어떤 레코드만 남길지에 대한 조건(부모테이블.PK = 자식테이블.FK)
-- cross조인에서 유효한 것만 추출해서 inner조인처럼 만든 것
select * from tblCustomer
cross join tblSales
where tblCustomer.seq = tblSales.cseq; -- 사용안함
-- ORA-00918: column ambiguously defined (열의 정의가 애매합니다.)
-- 조인을 할 때 자주 발생하는 현상
-- select seq from tblCustomer -> seq가 양쪽 테이블의 어느 것인지 알 수 없음
select
tblCustomer.seq, tblSales.seq
from tblCustomer -- 조인에서 컬럼은 반드시 테이블명(소유주)을 적는게 좋다. (충돌 발생) ★★
inner join tblSales
on tblCustomer.seq = tblSales.cseq;
-- 보고 싶은 내역만 구분해서 가져오기
select
tblCustomer.name, -- 테이블명을 붙이면 가독성이 좋아진다.
tblCustomer.address,
tblSales.item,
tblSales.qty
from tblCustomer
inner join tblSales
on tblCustomer.seq = tblSales.cseq;
-- 테이블 별칭은 as를 쓰지 않는다. (보통은 1글자로 만든다.)
select
c.name,
c.address,
s.item,
s.qty
from tblCustomer c
inner join tblSales s
on c.seq = s.cseq;
select * from tblStaff;
select * from tblProject;
select
s.name as 직원명,
s.salary as 급여,
p.project as 프로젝트명
from tblStaff s
inner join tblProject p
on s.seq = p.staff_seq;
-- FK안한 관계있는 테이블끼리 Join
select * from tblMen;
select * from tblWomen;
select
m.name as 남자,
f.name as 여자
from tblMen m
inner join tblWomen f
on m.couple = f.name;
-- 전혀 관계없는 케이블끼리 join -> 의미없음.. -> join이 된다고 해도 무조건 하면 XXX
select * from tbladdressbook;
select * from tblComedian;
select * from tbladdressbook a
inner join tblcomedian c
on a.height = c.height;
-- 직원의 이름과 부서명을 가져오시오.
select * from locations;
select * from employees;
select * from departments;
-- 상관서브쿼리
select
first_name || last_name as name,
-- department_id,
(select department_name from departments where department_id = employees.department_id) as department
from employees;
-- inner join (3개 테이블)
select
e.first_name || ' ' || e.last_name as name,
d.department_name,
l.city || '' || l.street_address
from employees e
inner join departments d
on d.department_id = e.department_id
inner join locations l
on l.location_id = d.location_id;
select * from tblgenre;
select * from tblvideo;
-- tblgenre + tblvideo
select
*
from tblgenre g
inner join tblvideo v
on g.seq = v.genre;
-- tblgenre + tblvideo + tblRent
select
*
from tblgenre g
inner join tblvideo v
on g.seq = v.genre
inner join tblRent r
on v.seq = r.video;
-- tblgenre + tblvideo + tblRent + tblMember
select * from tblgenre;
select
g.price as 대여가격,
g.period as 대여기간,
v.name as 비디오제목,
m.name as 회원명,
r.rentdate as 대여날짜,
r.rentdate + g.period 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 tblStaff; -- 부모 테이블
select * from tblProject; -- 자식 테이블
-- 내부 조인
-- : 2개 테이블에 on 조건을 만족하는 레코드만 반환
-- : 내부 조인의 결과는 대부분 자식 레코드 수만큼 나온다.
select
*
from tblStaff s
inner join tblProject p
on s.seq = p.staff_seq;
-- 비디오 가게 사장
-- : 출근 > 어떤 회원?이 뭘 대여? 반납O,X?
select
m.name as 이름,
v.name as 타이틀,
r.retdate as 반납여부
from tblMember m
inner join tblRent r
on m.seq = r.member
inner join tblvideo v
on v.seq = r.video;
-- inner join은 양쪽 테이블에 존재하는 데이터만 가져온다.(교집합)
select * from tblCustomer; -- 3명 -> 4명
select * from tblSales; -- 9명
-- 신규 가입 회원은 아직 구매 이력이 없다.(****)
insert into tblCustomer values (4,'호호호','010-8745-9652', '서울시');
-- 구매 이력과 구매 이력이 있는 회원정보를 가져오세요.
select * from tblcustomer c
inner join tblSales s
on c.seq = s.cseq;
select * from tblCustomer; -- 부모 -> 고객명, 연락처
select * from tblSales; -- 자식 -> 제품명, 수량
-- join
select
c.name,
c.tel,
s.item,
s.qty
from tblCustomer c
inner join tblSales s
on c.seq = s.cseq;
-- sub Query(상관 서브 쿼리) -> 자식 테이블이 메인이 되어야한다.
select item, qty, cseq,
(select name from tblCustomer where tblCustomer.seq = tblSales.cseq)as name,
(select tel from tblCustomer where tblCustomer.seq = tblSales.cseq) as tel
from tblSales;
-- 구매 이력과 상관없이 모든 회원 정보를 가져오되, 구매 이력이 있으면 구매이력도 같이 가져오시오.
-- tblcustomer(부모테이블) 를 가르킨다.
select * from tblcustomer c left outer join tblSales s on c.seq = s.cseq; -- 물건을 한번도 안 산 신규회원 포함
select * from tblcustomer c right outer join tblSales s on c.seq = s.cseq;
-- 대여 유무 이력과 상관없이 모든 회원 정보 + 대여기록
select
m.name as 이름,
r.rentdate,
r.retdate as 반납여부
from tblMember m
left outer join tblRent r
on m.seq = r.member;
select
distinct
m.name as 이름,
case
when r.rentdate is not null then '우량회원'
when r.rentdate is null then '불량회원'
end as 종류
from tblMember m
left outer join tblRent r
on m.seq = r.member
order by 종류 desc, name asc;
-- 어떤 비디오가 몇번 빌려갔는지?
select
v.name,
count(r.rentdate) as 대여횟수
from tblVideo v
left outer join tblRent r
on v.seq = r.video
group by v.name
order by count(r.rentdate) desc, v.name asc;
-- 직원테이블
-- 테이블 생성
create table tblSelf(
seq number primary key, -- 직원번호(PK)
name varchar2(30) not null, -- 직원명
department varchar2(50) null, -- 부서명
super number null references tblSelf(seq) -- 상사번호(FK), 자기참조
);
-- 데이터
insert into tblSelf values (1,'홍사장', null, null);
insert into tblSelf values (2,'김부장', '영업부', 1);
insert into tblSelf values (3,'이과장', '영업부', 2);
insert into tblSelf values (4,'정대리', '영업부', 3);
insert into tblSelf values (5,'최사원', '영업부', 4);
insert into tblSelf values (6,'박부장', '개발부', 1);
insert into tblSelf values (7,'하과장', '개발부', 6);
select * from tblSelf;
-- 직원명, 소속부서, 상사명을 가져오시오.
-- 재귀 형태
-- 홍사장 미포함
select
s1.name as "직원명",
s1.department as "소속부서",
s2.name as "상사명"
from tblSelf s1 -- 직원(부하)
inner join tblSelf s2 -- 상사
on s1.super = s2.seq; -- 중요 ********
-- 홍사장 포함
select
s1.name as "직원명",
s1.department as "소속부서",
s2.name as "상사명"
from tblSelf s1 -- 직원(부하)
left outer join tblSelf s2 -- 상사
on s1.super = s2.seq; -- 중요 ********
select * from tblMen;
select * from tblWomen;
-- 커플인 남자와 여자를 가져오세요. -> 솔로는 안가져옴
select
m.name as 남자, w.name as 여자
from tblMen m
inner join tblWomen w
on m.couple = w.name;
-- 모든 남자(outer join) + 여자친구가 있으면 여자친구 이름도 같이
select
m.name as 남자, w.name as 여자
from tblMen m
left outer join tblWomen w
on m.couple = w.name;
-- 모든 여자(outer join) + 남자친구가 있으면 남자친구 이름도 같이
select
m.name as 남자, w.name as 여자
from tblMen m
right outer join tblWomen w
on m.couple = w.name;
-- 모든 남자 + 모든 여자 + 커플이 있으면 커플이름도 같이
select
m.name as 남자, w.name as 여자
from tblMen m
full outer join tblWomen w
on m.couple = w.name
order by m.name asc;