SET 연산 : 2개 이상의 테이블로부터 데이터를 추출하는 방법 중 하나
SET 연산자를 이용해서 여러개의 SELECT 문장을 연결해서 사용이 가능하다
SELECT 구문
SET operator
SELECT 구문
[ORDER BY]
-- UNION
SELECT DEPTNO
FROM DEPT
UNION
SELECT DEPTNO
FROM EMP;

-- UNION ALL
SELECT DEPTNO
FROM DEPT
UNION ALL
SELECT DEPTNO
FROM EMP;

-- INTERSECT
SELECT DEPTNO
FROM DEPT
INTERSECT
SELECT DEPTNO
FROM EMP;

-- EXCEPT
SELECT DEPTNO
FROM DEPT
EXCEPT
SELECT DEPTNO
FROM EMP;

서브 쿼리는 하나의 SQL 문장 안의 절에 포함된 SQL
인라인 뷰(View)서브 쿼리(Sub Query)단일 행 Sub Query 와 다중 행 Sub Query로 나눈다
SELECT DNAME
FROM DEPT
WHERE DEPTNO = ( SELECT DEPTNO FROM EMP WHERE ENAME='MILLER' )
서브쿼리 먼저 해석하고 메인쿼리를 해석한다.
단일 행 서브쿼리는 수행 결과가 오직 하나의 행을 반환하는 서브쿼리이다. 하나의 행을 반환하기 때문에 단일행 비교 연산자인 =, >, <, >=, <=, <>를 사용하는 것이 가능하다
-- 에러
SELECT MAX(POPU),NAME
FROM tCity
-- 에러
SELECT NAME, popu
FROM tCity
where popu = max(popu);
첫 문장이 에러인 이유 - 그룹함수는 그룹화하지 않은 컬럼과 같이 조회할 수 없음.
두번째 문장은 그룹 함수를 where 절에 사용해서 에러가 난다.
인구의 최대값을 먼저 구해서 조회한 뒤 인구수가 최대값고 동일한 데이터를 조회해야한다.
SELECT NAME, popu
FROM tCity
where popu = (select max(popu) from tcity);

select ename, sal
from emp
where sal >= (select avg(sal) from emp);

select ename, deptno
from emp
where deptno = (select deptno from dept where lower(loc) = 'dallas');

다중열 서브쿼리는 서브쿼리의 결과가 여러개의 열인 경우이다.
-- 단일 행 서브쿼리 이용
select *
from tstaff
where depart = (select depart from tstaff where name = '안중근') AND GENDER = (select GENDER from tstaff where name = '안중근')
-- 다중열 서브쿼리 이용, 여러 열을 한꺼번에 비교
select *
from tstaff
where (depart, gender) = (select depart, gender from tstaff where name = '안중근')

Sub Query에서 반환되는 결과가 하나 이상의 행일 때 사용하는 Sub Query
이 경우에는 단일 행 연산자를 사용하면 에러가 발생한다
IN : 목록에 포함되면 된다
ANY SOME : 하나라도 일치하면 된다
ALL : 전부 일치
EXIST : 하나라도 일치하면 참을 리턴한다
이때 ANY와 ALL은 MAX나 MIN 함수로 대체가 가능하다
서브 쿼리가 여러개의 행을 반환할 때 그 중 하나의 값과 일치하는 데이터를 조회할 때는 IN 연산자 사용
-- in 연산자 사용
select empno, ename, sal, deptno
from emp
where sal in (select max(sal) from emp group by deptno);

메인쿼리의 비교조건이 서브쿼리의 검색 결과와 모든 값이 일치하면 TRUE
잘 해석하면 MAX나 MIN 함수로 대체 가능합니다
-- DEPTNO 가 30인 데이터의 SAL을 조회 : 6개 조회
SELECT SAL
FROM EMP
WHERE DEPTNO = 30
-- 위에서 검색된 데이터보다 전부 큰 SAL을 가진 데이터르 조회
SELECT ENAME, SAL
FROM EMP
WHERE SAL > ALL(SELECT SAL FROM EMP WHERE DEPTNO = 30);
-- ALL은 MAX보다 크면 되기 때문에 대체 가능하다
SELECT ENAME, SAL
FROM EMP
WHERE SAL > (SELECT MAX(SAL) FROM EMP WHERE DEPTNO = 30);

여러개의 데이터 중 하나만 조건을 만족하면 TRUE
ALL과 마찬가지로 MIN이나 MAX함수를 이용해서 대체가 가능하다
SELECT ENAME, SAL
FROM EMP
WHERE SAL > ANY(SELECT SAL FROM EMP WHERE DEPTNO = 30);
-- ANY은 MIN보다 크면 되기 때문에 대체 가능하다
SELECT ENAME, SAL
FROM EMP
WHERE SAL > (SELECT MIN(SAL) FROM EMP WHERE DEPTNO = 30);

select ename, sal, job
from emp
where (sal > (select min(sal) from emp where job = 'salesman')) and job <> 'salesman'

데이터의 존재 여부를 리턴
EXISTS의 구문이 참이 되면 전부 출력
SELECT ENAME, SAL
FROM EMP
WHERE EXISTS(SELECT 1 FROM EMP WHERE SAL >= 2000)

SELECT ENAME, HIREDATE
FROM EMP
WHERE DEPTNO = (SELECT DEPTNO FROM EMP WHERE ENAME = 'BLAKE') AND ENAME <> 'BLAKE';

SELECT EMPNO, ENAME
FROM EMP
WHERE SAL > (SELECT AVG(SAL) FROM EMP)
ORDER BY SAL DESC;

SELECT EMPNO, ENAME, SAL
FROM EMP
WHERE DEPTNO IN (SELECT DEPTNO FROM EMP WHERE ENAME LIKE '%T%')
ORDER BY EMPNO;

select ename, JOB,SAL
from emp
where deptno = (select deptno from dept where lower(loc) = 'dallas');
-- MGR = 관리자 사원번호 - MANAGER의 MGR : 7839
SELECT ENAME, SAL
FROM EMP
WHERE MGR = (SELECT EMPNO FROM EMP WHERE ENAME = 'KING');

SELECT *
FROM EMP
WHERE SAL > (SELECT MIN(SAL) FROM EMP WHERE DEPTNO = 30);

EMPT 테이블과 DEPT 테이블은 부서번호인 DEPTNO 컬럼을 모두 가지고 있다.
XCatesian Product 라고도 하는데 별다른 조인 조건 없이 from절에 2개 테이블 이상을 나열하는 경우 발생데이터 14개
열 8개

데이터 4개
열 3개

EMP X DEPT
select *
from emp,dept;
데이터 56개 = 14 * 4
열 11개 = 8 + 3
결과는 모든 데이터의 조합이 나오므로 행의 개수는 곱한 것과 같고, 열의 개수는 더한 것과 같다.
테이블이름.컬럼이름으로 조인조건을 기술해야 한다SELECT *
FROM EMP,DEPT
WHERE EMP.DEPTNO = DEPT.DEPTNO;
데이터 14개, 열 11개
DEPTNO가 일치하는 애들끼리 매칭되어서 JOIN 된다.
SELECT *
FROM EMP,DEPT
WHERE EMP.DEPTNO = DEPT.DEPTNO AND ENAME = 'MILLER';
SELECT ENAME, DNAME
FROM EMP,DEPT
WHERE EMP.DEPTNO = DEPT.DEPTNO;
테이블 이름.컬럼으로 기술해야 한다. 그렇지 않으면 애매한 컬럼이름이라고 에러가 발생한다. 테이블 이름을 변경해서 사용할 수 있는데 FROM 절 다음에 테이블 이름을 명시하고 공백을 둔 다음에 다른 이름을 지정 - EMP E 별명이 아니라 테이블 이름이 바뀐 것이기 때문에 이후 절에서는 테이블 이름을 사용할 때 다른 이름을 사용해야한다.
SELECT *
FROM EMP E,DEPT D
WHERE E.DEPTNO = D.DEPTNO;
SELECT ENAME, SAL
FROM EMP, DEPT
WHERE EMP.DEPTNO = DEPT.DEPTNO AND LOC = 'NEW YORK';
-- 서브쿼리 이용
SELECT ENAME, SAL
FROM EMP
WHERE DEPTNO = (SELECT DEPTNO FROM DEPT WHERE LOC = 'NEW YORK');
조회하고자 하는 컬럼들이 하나의 테이블에 존재하는 경우는 조인 대신 서브쿼리 이용이 가능하고 서브쿼리를 이용하는 것이 효율적이다. 조인을 하면 테이블이 커지기 때문에 조인은 회피하는 것이 좋다. 대신 조인을 하지 않게되면 쿼리문이 길어진다.

SELECT ENAME, HIREDATE
FROM EMP, DEPT
WHERE EMP.DEPTNO = DEPT.DEPTNO AND DNAME = 'ACCOUNTING';

SELECT *
FROM SALGRADE;
SELECT *
FROM EMP;


두 테이블의 값이 같은걸 찾는 게 아닌 특정 범위 내에 잇는지 조사하기 위함이다.
이 경우에는 SAL이 LOSAL과 HISAL 사이에 있는 조건을 가지고 조회를 해야한다.
이렇게 다른 테이블의 데이터와 = 이 아닌 다른 연산자로 비교하는 경우는 NON EQUI JOIN 이라고 한다.
SELECT ENAME, SAL, GRADE
FROM SALGRADE, EMP
where SAL between LOSAL and HISAL;

SELECT CONCAT(E.ENAME, '의 매니저는', M.ENAME)
FROM EMP E, EMP M
WHERE E.MGR = M.EMPNO;

SELECT E.ENAME, E.JOB
FROM EMP E, EMP M
WHERE E.MGR = M.EMPNO AND M.ENAME = 'KING';

-- CROSS JOIN
FROM 테이블이름, 테이블이름
-- ANSI JOIN
FROM 테이블이름 CROSS JOIN 테이블이름
FROM 테이블 이름 INNER JOIN 테이블이름
ON 조인조건
SELECT ENAME, DNAME
FROM EMP INNER JOIN DEPT
ON EMP.DEPTNO = DEPT.DEPTNO
WHERE ENAME = 'MILLER';

USING (컬럼이름) 을 사용해도 된다SELECT ENAME, DNAME
FROM EMP INNER JOIN DEPT
USING (DEPTNO)
WHERE ENAME = 'MILLER';
SELECT *
FROM 테이블 이름 NATURAL JOIN 테이블이름
SELECT ENAME, DNAME
FROM EMP NATURAL JOIN DEPT
WHERE ENAME = 'MILLER';
SELECT *
FROM 테이블 이름 [LEFT | RIGHT | FULL] OUTER JOIN 테이블이름
EMP 테이블 - DEPTNO 10 20 30
DEPT 테이블 - DEPTNO 10 20 30 40
INNER JOIN 결과 - DEPTNO 10 20 30
select *
FROM EMP RIGHT OUTER JOIN DEPT
ON EMP.DEPTNO = DEPT.DEPTNO;
OUTER JOIN 결과 - DEPTNO 10 20 30 40

MariaDB에는 FULL OUTER JOIN이 없기 때문에 SET 연산을 이용해서 FULL OUTER JOIN을 구현한다.
select *
FROM EMP LEFT OUTER JOIN DEPT
ON EMP.DEPTNO = DEPT.DEPTNO;
UNION
select *
FROM EMP RIGHT OUTER JOIN DEPT
ON EMP.DEPTNO = DEPT.DEPTNO;
-- EQUI JOIN
SELECT E.ENAME, E.DEPTNO,D.DNAME
FROM EMP E,DEPT D
WHERE E.DEPTNO = D.DEPTNO;

-- EQUI JOIN
SELECT E.ENAME, E.JOB, E.SAL, D.DNAME
FROM EMP E,DEPT D
WHERE E.DEPTNO = D.DEPTNO AND D.LOC = 'NEW YORK';

-- INNER JOIN
SELECT E.ENAME, D.DNAME, D.LOC
FROM EMP E INNER JOIN DEPT D
USING (DEPTNO)
WHERE E.COMM IS NOT NULL;

-- INNER JOIN
SELECT E.ENAME,E.JOB, D.DNAME, D.LOC
FROM EMP E INNER JOIN DEPT D
USING (DEPTNO)
WHERE E.ENAME LIKE '%L%';

-- SELF JOIN
SELECT E.ENAME, E.HIREDATE, M.ENAME, M.HIREDATE
FROM EMP E,EMP M
WHERE E.MGR = M.EMPNO AND M.HIREDATE > E.HIREDATE;
