매일공부

[SQL 입문] 데이터 결합; JOIN 검색 본문

Programming/SQL

[SQL 입문] 데이터 결합; JOIN 검색

aram 2022. 8. 22. 21:53

- JOIN이란?

: 2개 이상의 테이블로부터 동일속성의 값이 일치할 때 레코드를 결합해서 결과집합으로 생성
: 가로로 join

- JOIN 종류

  • equi join (inner join)
    • 동일 속성값이 일치할 때 조인 수행,
    • = 연산자가 조인 조건에 사용됨(일치하지 않는 절은 제외 됨)
    • parent.pk = child.fk.컬럼으로 조인 조건이 선언됨
    • [ SELECT 컬럼 FROM 테이블1 a, 테이블2 b WHERE a.컬럼명 = b.컬럼명 ;
  • inner join
    • equi join과 동일 목적으로 시행
    • [ SELECT 컬럼 FROM 테이블1 a INNER JOIN 테이블2 b ON a.컬럼명 = b.컬럼명 (WHERE~) ; ] 
  • natural join
    • inner join의 하위 개념
    • 두 테이블에서 동일한 이름을 가진 모든 열을 기준으로 자동으로 오라클서버가 조인 수행
      (동일 속성 컬럼에 대해서 alias 또는 테이블명 사용X)

    • 두 테이블에서 동일한 이름의 컬럼타입이 다른 경우 조인을 수행하면 오류발생
    • 두 테이블에서 동일한 속성의 컬럼이지만, 컬럼 이름이 다르게 설계된 경우에는 조인되지 못함
    • [ SELECT 컬럼 FROM 테이블1 NATURAL (INNER) JOIN 테이블2 ; ] 
  • join ~ on 조건절
    • 동일 속성의 컬럼 이름이 다를 경우 사용
  • join ~ using 조건절
    • 두 테이블에서 동일 이름의 속성 하나로만 조인
    • 원하는 컬럼에 대해서만 equi join 가능
    • 동일이름의 컬럼 속성  앞에 소유자 테이블명이나 alias 사용X
    • {SELECT 컬럼 FROM 테이블1 [INNER] JOIN 테이블2 USING (공통컬럼) [WHERE~] ; }  - [] = 생략가능 
  • non-equi join
    • 동일속성, 동일 컬럼명, 동일속성값이 존재하지 않는 경우
    • =연산자가 아닌 다른 연산자를 조인 조건에 사용됨
  • self join
    • 하나의 테이블에서 서로 다른 레코드들 간에 조인이 수행됨
    • 자기 참조 관계가 있는 테이블만 가능 > pk를 참조하는 fk가 동일테이블에 존재하는 경우만 가능
    • [ SELECT 컬럼 FROM 테이블1 a JOIN 테이블1 b ON a.pk_컬럼명 = b.fk_컬럼명 (WHERE~) ; ] 
  • outer join
    • (+)left outer join / right outer join / full outer join
    • equi 조인에서 한쪽의 조인 컬럼값이 null인 경우 결과집합에서 누락되므로, 조인 결과집합으로 가져오기 위한 조인 방식
    • 결과 집합에 포함될 레코드가 존재하는 테이블을 기준 테이블outer join을 수행함
    • [ SELECT 컬럼 FROM 테이블1 a  LEFT|RIGHT|FULL JOIN 테이블2 b ON a.컬럼명 = b.컬럼명 (WHERE~) ; ] 
  • cartesian product(cross join)
    • 하나의 레코드가 조인할 테이블의 모든 레코드와 한번씩 조인을 수행 > 15rows*4rows = 60rows(결과)
    • 시행되는 경우
      : 조인조건이 누락 > join 수행의 논리적 오류 
      : 조인 레코드가 존재하지 않는 경우 > join 수행의 논리적 오류 
    • 시뮬레이션을 위해 레코드 수를 늘려서 테스트 수행하고자 할 때, 의도적으로 cartesian product결과를 만들기도 함.
    • [ SELECT 컬럼 FROM 테이블1, 테이블2 ; ]  --오라클 only
    • [ SELECT 컬럼 테이블1 CROSS JOIN 테이블2 ( WHERE~) ; ]  --ANSI 표준

 

- oracle db에서 제공하는 SQL 1999문법

 : 이전엔 where 절에서 조인 조건 선언
   > cartesian product의 문제가 발생하기도 함
 : sql3표준(1999)에서 변경됨
   > FROM절에서 JOIN 조건 선언으로 변경됨


-- cross join / natural join

Q. emp, dept 테이블에서 사원들에 대해서 사번, 이름, 부서번호, 부서이름을 조회

더보기
SELECT empno, ename, deptno, dname
FROM emp, dept; --error : 열의 정의가 애매합니다 >> 어느테이블에서 가져와야하는지 모름

SELECT emp.empno, emp.ename, emp.deptno, dept.dname
FROM emp, dept; --메타 정보를 확인하기 위해 recursive sql 수행 횟수를 줄이고, 성능 개선

SELECT e.empno, e.ename, e.deptno, d.dname
FROM emp e, dept d; 
-- 14rows X 4rows = 56건
-- 조인조건이 누락되면 cartesian product, cross join(sql3 표준)으로 실행 됨


-- equi join 활용

더보기
SELECT e.empno, e.ename, e.deptno, d.dname
FROM emp e, dept d
WHERE e.deptno = d.deptno; --조인 조건, equi join


-- inner join으로 한다면?

더보기
select e.empno, e.ename, e.deptno, d.dname
from emp e (inner) join dept d on e.deptno = d.deptno;


-- oracle db에서 제공하는
equi join방식의 sql 1999문법 > natural join

더보기
SELECT e.empno, e.ename, e.deptno, d.dname  --e.ename, "e."deptno 이것때문에 error
FROM emp e natural join dept d;

SELECTe.empno, e.ename, deptno, d.dname  --e.deptno > deptno로 하면 실행 가능
FROM emp natural join dept;

SELECT ename, deptno, dname, loc  --아예 alias를 사용 안해도 자동으로 수행해 줌
FROM emp natural join dept;


-- join ~using

Q. employees , departments 테이블로부터 사번, 이름, 부서번호, 부서이름을 조회

더보기
SELECT e.employee_id, e.last_name, department_id, d.department_name
FROM employees e natural join departments d
    --12rows 
    >> 두 테이블에 동일한 이름을 가진 열이 department_id와 manager_id
    >> 그래서 department_id와 manager_id 컬럼값이 모두 일치할 때 조인이 수행됨)
SELECT e.employee_id, e.last_name, d.department_id, d.department_name
FROM employees e, departments d 
WHERE e.department_id = d.department_id;
   --19rows >> 178번 사원의 부서번호가 null이므로 조인되지 못하고 누락됨
SELECT e.employee_id, e.last_name, a. department_id, d.department_name
FROM employees e join departments d using (department_id); -error
-- join ~using에 사용되는 동일이름의 컬럼 속성 앞에 소유자 테이블명이나 alias를 사용할 수 없음

SELECT e.employee_id, e.last_name, department_id, d.department_name
FROM employees e join departments d using (department_id);

 


-- 앞서 계정을 만들고 권한까지 부여했던 scott 계정에 DB생성

create table emp20
as select empno, ename, deptno deptid, sal, job
from emp
where deptno = 20; --테이블의 구조와 일부 레코드가 복제, CATS

desc emp20
select * from emp20; --생성된 테이블 확인


-- join ~ on 

select e.empno, e.ename, e.deptid, d.dname
from emp20 e natural join dept d;
  --논리적인 error. 동일속성이지만, 컬럼이름이 다르므로 >> 5rows*4rows cartesian product로 수행됨

select e.empno, e.ename, e.deptid, d.dname
from emp20 e join dept d on e.deptid = d.deptno;  --동일 속성의 컬럼 이름이 다르면 join ~ on 사용


-- non-equi join(= 연산자 사용x)

Q. 사원별로 급여와 급여의 등급을 조회결과 생성 > between ~ and ~ 와 같은 연산자 사용

더보기

-- salgrade 등급, 급여 하한값, 상한값

SELECT e.empno, e.ename, e.sal, s.grade
FROM emp e, salgrade s
WHERE e.sal between s.losal and s.hisal; --non-equi join

SELECT e.empno, e.ename, e.sal, s.grade
FROM emp e join salgrade s on e.sal between s.losal and s.hisal;


-- self join이 가능한 테이블 : 자기참조 관계가 존재하는 테이블(pk를 참조하는 fk가 동일테이블에 존재하는 경우)

Q. 사원번호, 사원이름, 관리자번호, 관리자이름 조회 결과 생성

더보기
SELECT a.empno, a.ename, a.mgr, b.ename
FROM emp a, emp b
WHERE a.mgr = b.empno;

--sql1999문법 self join
SELECT a.empno, a.ename, a.mgr, b.ename
FROM emp a join emp b on a.mgr = b.empno;

 


conn c##scott/oracle
desc employees
desc departments
desc locations


-- n개의 테이블을 조인할 때 > 최소 n-1개의 조인 조건을 선언

Q. 사원이름(last_name), 부서이름(department_name), 부서위치한 도시(city) 출력 > 3개의 테이블 join

더보기
SELECT a.last_name, b.department_name, c.city
FROM employees a, departments b, locations c
WHERE a.department_id = b.department_id
and c.location_id = b.location_id;

 ---sql1999문법 ansi표준문법
SELECT a.last_name, b.department_name, c.city
FROM employees a 
    join departments b on a.department_id = b.department_id
    join locations c on c.location_id = b.location_id;

 


-- NULL체크를 위해 의도적으로 '홍길동' 사원 추가

conn c##hr/oracle
insert into emp (empno, ename)
values (7000, '홍길동');
commit;


-- 조인 컬럼값이 null > pk와 fk equi 조인 조건에서는 조인되지 못해서 조인 결과에 누락  > outer join 수행
-- where 절에 조인조건 선언하려면 > 조인할 레코드가 없는 테이블의 조인조건에 (+) 선언

Q. 부서를 아직 배정받지 못한 사원을 포함하여 사원들의 부서번호와 부서이름을 출력(15rows)

더보기
SELECT a.ename, a.deptno, b.dname, b.loc
FROM emp a, dept b
WHERE a.deptno = b.deptno; --방금 추가한 홍길동 사원 = NULL이라서 누락
SELECT a.ename, a.deptno, b.dname, b.loc
FROM emp a, dept b
WHERE a.deptno = b.deptno(+); --dept에 NULL

SELECT a.ename, a.deptno, b.dname, b.loc
FROM emp a left outer join dept b on a.deptno = b.deptno;


-- sql 1999 문법에서는 결과 집합에 포함될 레코드가 존재하는 테이블을 기준 테이블로 outer join을 수행

Q. 부서별 사원정보를 출력(40번 부서 정보 조인 결과로 생성하도록 sql 작성)

더보기
SELECT b.deptno, b.dname, a.empno, a.ename
FROM emp a, dept b
WHERE a.deptno = b.deptno
ORDER BY 1 asc; ---40번 부서 정보 조인 결과 누락
SELECT b.deptno, b.dname, a.empno, a.ename
FROM emp a, dept b
WHERE a.deptno(+) = b.deptno  --조인할 레코드가 없는 곳에 조인 연산자 추가
ORDER BY 1 asc;

SELECT b.deptno, b.dname, a.empno, a.ename
FROM emp a right outer join dept b on a.deptno = b.deptno
ORDER BY 1 asc;


-- 만약 조인할 레코드에 없는 곳(NULL)이 아닌 반대로 한다면?

더보기
SELECT b.dname, b.deptno, a.empno, a.ename
FROM emp a, dept b
WHERE a.deptno = b.deptno(+)
ORDER BY 1 asc; --원하는 결과의 반대로 나옴


- full join : left join으로 추가 되는 행 + right join으로 추가되는 행

Q. 7000번 사원 레코드와 40번 부서 정보 레코드를 모두 조인 결과로 생성

더보기
SELECT b.dname, b.deptno, a.empno, a.ename
FROM emp a, dept b
WHERE a.deptno(+) = b.deptno(+)  --오류남 > (+) 연산자로는 수행 불가
ORDER BY 1 asc;

SELECT b.deptno, b.dname, a.empno, a.ename
FROM emp a full outer join dept b on a.deptno = b.deptno
ORDER BY 1 asc;

  -- left join과 right join에서 추가 되는 셀이 합쳐지는게 아니라 각각 모두 검색되어서 출력


-- cross join

SELECT b.dname, b.deptno, a.empno, a.ename
FROM emp a cross join dept b; --15rows*4rows = 60rows

 

* 내용참고&출처 : 태그의 수업을 복습 목적으로 정리한 내용입니다.

728x90
Comments