edu day 5
: 조건을 만족하지 않아도 결과값에 포함시키는 조인 방법으로 (+) 연산자를 사용한다.
(<--> 조인 조건에 일치하는 데이터만 조회하는 조인은 Inner조인이라고 한다.)
SELECT 테이블1.컬럼 , 테이블2.컬럼
FROM 테이블1 , 테이블2
WHERE 테이블1.공통컬럼 = 테이블2.공통컬럼 (+);
(+) 연산자를 지정하면 내부적으로 한 개 이상의 널(NULL)을 가진 행이 생성되고 이렇게 생성된 널(NULL)행들과 데이터를 가진 테이블의 행들이 조인하게 되어 조건이 일치하지 않아도 결과 값에 포함이 된다.
! (+)연산자를 동시에 사용할 수는 없으며, 반드시 하나의 테이블에만 지정해야 된다.
SELECT E.ENAME 사원명, E.EMPNO 사번, M.ENAME 관리자명, M.EMPNO 관리자번호 FROM EMP E, EMP M WHERE e.MGR = m.empno(+);
SELECT E.ENAME 사원, M.ENAME 관리자, MM.ENAME 관리자의관리자 FROM EMP E, EMP M, EMP MM WHERE E.MGR = M.EMPNO AND M.MGR = MM.EMPNO;
SELECT E.ENAME 사원, M.ENAME 관리자, MM.ENAME 관리관리자 FROM EMP E, EMP M, EMP MM WHERE E.MGR = M.EMPNO(+) AND M.MGR = MM.EMPNO(+);
: 조인 조건을 WHERE절에 명시하지 않고 다른 방법을 통하여 기술하며 검색조건을 지정하는 경우에 WHERE절을 사용한다.
: Oracle JOIN의 Equi JOIN과 기능이 동일하다. 조인에 참여하는 테이블은 반드시 한 개의 공통 컬럼이 있어야 되며, 만약 두 개 이상의 공통 컬럼이 있다면 엉뚱한 실행결과가 출력된다.
SELECT 테이블1.컬럼 , 테이블2.컬럼
FROM 테이블1 NATURAL JOIN 테이블2
[WHERE 검색조건];
공통 컬럼인 DEPTNO를 SELECT할 때 앞에 테이블 이름이나 별칭을 지정해줄 수 없다. -> 공통 컬럼이기 때문
! E.DEPTNO 또는 D.DEPTNO가 아닌 그냥 DEPTNO로 써야한다.
CROSS JOIN
: 조인할 때 일치하는 데이터만 반환하지 않고 조인하는 각 테이블 의 행 개수를 서로 곱한 결과가 반환된다. 데이터로서의 가치는 없다.
: NATURAL 조인 사용시 만약 두 개 이상의 공통 컬럼이 있다면 USING절을 사용하여 명시적으로 어떤 컬럼으로 조인할 지를 지정할 수 있다.
SELECT 테이블1.컬럼 , 테이블2.컬럼
FROM 테이블1 [INNER] JOIN 테이블2 USING(공통컬럼)
[WHERE 검색조건];
SELECT * FROM EMP JOIN DEPT USING(DEPTNO);
: 만약 NON-Equi JOIN이나 임의의 조건으로 조인할 경우에는 ON절을 사용해야 된다. 동등/비동등 형식.
또한 TABLE JOIN할때 WHERE을 안써줬기 때문에 조건을 추가 할때는 WHERE을 써준다.
SELECT 테이블1.컬럼 , 테이블2.컬럼
FROM 테이블1 [INNER] JOIN 테이블2 ON 조인조건
[WHERE 검색조건];
SELECT * FROM EMP E JOIN DEPT D ON E.DEPTNO = D.DEPTNO;
주의!! USING절은 공통컬럼이 하나만 생성되고 ON절은 공통컬럼이어도 각 테이블마다의 컬럼이 생기기 때문에 컬럼에 별칭을 지정해야 한다.
-- USING절과 ON절
SELECT ENAME, E.DEPTNO, DNAME FROM EMP E JOIN DEPT D ON E.DEPTNO = D.DEPTNO WHERE ENAME='SMITH';
SELECT ENAME, DEPTNO, DNAME FROM EMP JOIN DEPT USING (DEPTNO) WHERE ENAME = 'SMITH';
SELECT * FROM EMP E JOIN DEPT D USING(DEPTNO) JOIN SALGRADE S ON e.sal BETWEEN S.LOSAL AND S.HISAL;
SELECT DNAME 부서명, ENAME 이름, grade 월급등급, SAL 월급 FROM EMP E JOIN DEPT D USING(DEPTNO) JOIN salgrade S ON E.SAL BETWEEN S.LOSAL AND S.HISAL WHERE DEPTNO = 10;
SELECT E.ENAME 사원이름, M.ENAME 관리자이름, MM.ENAME 관리자의관리자이름 FROM EMP E JOIN EMP M ON E.MGR = M.EMPNO JOIN EMP MM ON M.MGR = MM.EMPNO WHERE E.ENAME = 'SMITH';
: Oracle JOIN에서는 (+)연산자를 사용하고 반드시 한 쪽 테이블에서만 사용할 수 있었다. ANSI JOIN에서의 OUTER조인은 LEFT | RIGHT | FULL 키워드를 이요하며 한 쪽 테이블 또는 양쪽 테이블 지정이 모두 가능하다.
SELECT 테이블1.컬럼 , 테이블2.컬럼
FROM 테이블1 LEFT|RIGHT|FULL OUTER JOIN 테이블2
ON 조인조건 | USING(컬럼)
[WHERE 검색조건];
LEFT OUTER JOIN은 LEFT로 지정된 테이블 1의 데이터를 테이블2의 조인조건 일치 여부와 상관없이 모두 출력한다는 의미이다. RIGHT도 테이블 2의 데이터를 테이블1의 조인조건 일치 여부와 상관없이 모두 출력한다는 의미이고, FULL OUTER JOIN은 LEFT OUTER JOIN 결과와 RIGHT OUTER JOIN 결과를 합친 결과이다.
ANSI JOIN 실습 문제
SELECT EMPNO, ENAME, SAL, DNAME FROM EMP E JOIN DEPT D USING(DEPTNO) WHERE SAL >= 2000 ORDER BY 3 DESC;
SELECT EMPNO, ENAME, JOB, SAL, DNAME FROM EMP E JOIN DEPT D USING(DEPTNO) WHERE JOB = 'MANAGER' AND SAL >=2500 ORDER BY 1;
SELECT EMPNO 사번, ENAME 사원명, SAL 급여, GRADE 등급 FROM EMP E JOIN SALGRADE S ON E.SAL BETWEEN S.LOSAL AND S.HISAL WHERE s.grade = 4 ORDER BY 3 DESC;
--1
SELECT E.ENAME 사원명, M.ENAME 관리자명, MM.ENAME 관리자의관리자명 FROM EMP E JOIN EMP M ON E.MGR = M.EMPNO JOIN EMP MM ON M.MGR = MM.EMPNO;
--2
SELECT E.ENAME 사원명, M.ENAME 관리자명, MM.ENAME 관리자의관리자명 FROM EMP E LEFT JOIN EMP M ON E.MGR = M.EMPNO LEFT JOIN EMP MM ON M.MGR = MM.EMPNO;
SELECT ENAME 이름, COMM 커미션, DNAME 부서이름 FROM EMP E JOIN DEPT D USING(DEPTNO) WHERE COMM IS NOT NULL AND COMM != 0;
SELECT E.ENAME 이름, E.SAL*12 연봉 FROM EMP E JOIN EMP M ON E.MGR = M.EMPNO WHERE E.SAL > M.SAL;
SELECT ENAME 이름, SAL 급여, HIREDATE 입사일, DNAME 부서명 FROM EMP E JOIN DEPT D USING(DEPTNO) WHERE (SYSDATE - HIREDATE)/365 > 30;
SELECT ENAME, SAL, HIREDATE, DNAME FROM EMP E JOIN DEPT D USING(DEPTNO) WHERE MONTHS_BETWEEN(SYSDATE, HIREDATE)/12 > 30;
SELECT DNAME 부서명, COUNT(*) 인원수 FROM EMP E JOIN DEPT D USING(DEPTNO) WHERE TO_CHAR(HIREDATE,'YY') < 82 GROUP BY DNAME;
SELECT category, COUNT(*) FROM TB_DEPARTMENT GROUP BY CATEGORY HAVING category LIKE '%학%'ORDER BY 2 DESC;
SELECT s.professor_name, s.professor_ssn FROM TB_PROFESSOR S JOIN TB_DEPARTMENT D USING(DEPARTMENT_NO) WHERE d.department_name='법학과' ORDER BY s.professor_ssn DESC;
SELECT CLASS_NAME, DEPARTMENT_NAME FROM TB_CLASS C JOIN TB_DEPARTMENT D USING(DEPARTMENT_NO) ORDER BY 2;
SELECT CLASS_NAME, PROFESSOR_NAME FROM TB_CLASS C JOIN tb_CLASS_professor P USING(class_no) JOIN TB_PROFESSOR CP USING(PROFESSOR_NO);
SELECT CLASS_NAME, PROFESSOR_NAME, CATEGORY FROM TB_CLASS C JOIN TB_CLASS_PROFESSOR CP USING(CLASS_NO) JOIN TB_PROFESSOR P USING(PROFESSOR_NO) JOIN TB_DEPARTMENT D ON c.department_no = D.department_no WHERE CATEGORY='인문사회';
: JOIN은 하나 이상의 테이블에서 원하는 데이터를 조회할 때 사용하는 방법이고, 서브쿼리는 하나의 SELECT만으로 원하는 데이터를 조회할 수 없을 때 사용하는 방법으로 여러 개의 SELECT 문장을 하나로 합쳐서 하나의 실행 가능한 SQL문장을 만들어 원하는 데이터를 조회한다.
1. 서브쿼리가 실행되고 2. 메인쿼리가 실행된다.
=> 서브쿼리를 먼저 작성하고 메인쿼리를 작성하면 편하다.
SELECT select_list
FROM 테이블
WHERE 컬럼명 연산자 (SELECT select_list
FROM 테이블);
SELECT ENAME, SAL FROM EMP WHERE SAL > (SELECT SAL FROM EMP WHERE ENAME = 'SMITH');
SELECT ENAME, DEPTNO FROM EMP WHERE DEPTNO = (SELECT DEPTNO FROM EMP WHERE ENAME = 'SMITH');
SELECT ENAME, DEPTNO FROM EMP WHERE DEPTNO = (SELECT deptno FROM DEPT WHERE DNAME='RESEARCH');
SELECT ENAME, SAL FROM EMP WHERE SAL > (SELECT AVG(SAL) FROM EMP);
: 오라클에서 사용 가능한 서브쿼리는 서브 쿼리가 실행되어 반횐된 행의 개수에 따라서 단일행 서브쿼리와 복수행 서브쿼리로 구분된다.

: 대표적으로 기본키를 이용하거나 MAX,MIN,SUM과 같은 그룹함수를 사용하여 검색하는 경우로서 반드시 단일행 연산자를 사용하여 메인 쿼리와 연산되어야 된다.
SELECT ENAME, SAL FROM EMP WHERE SAL < (SELECT MIN(SAL) FROM EMP WHERE DEPTNO = 10);
SELECT ENAME, HIREDATE FROM EMP WHERE HIREDATE < (SELECT HIREDATE FROM EMP WHERE ENAME = 'CLARK');
: 서브쿼리가 실행되어 반환되는 결과가 하나 이상의 행일 때 사용하는 서브쿼리이다. 반드시 복수형 연산자와 함께 사용해야 된다.

IN 연산자
: 서브쿼리 반환값이 복수이고 메인 쿼리와 동등 연산자 방식으로 비교할 때 사용하는 연산자
SELECT ENAME, SAL FROM EMP WHERE SAL IN (SELECT SAL FROM EMP WHERE ENAME IN ('SMITH', 'WARD'));SELECT DEPTNO, ENAME, SAL FROM EMP WHERE DEPTNO IN (SELECT DISTINCT DEPTNO FROM EMP WHERE SAL >= 2000);
ALL 연산자
: ALL연산자는 복수행 서브쿼리에서 > 또는 <같은 비교 연산자를 사용하고자 할 때 사용된다. > 또는 < 같은 연산자는 단일행 연산자이기 때문에 복수행 연산자에서 ALL 키워드 없이 사용하면 에러가 발생한다.

SELECT ENAME, SAL FROM EMP WHERE SAL > ALL(SELECT SAL FROM EMP WHERE DEPTNO = 30);
SELECT ENAME, SAL FROM EMP WHERE SAL < ALL(SELECT SAL FROM EMP WHERE DEPTNO = 30);
ANY 연산자
: 조건이 하나 이상만 만족하면 된다.

SELECT ENAME, SAL FROM EMP WHERE SAL > ANY(SELECT SAL FROM EMP WHERE DEPTNO = 30);
SELECT ENAME, SAL FROM EMP WHERE SAL < ANY(SELECT SAL FROM EMP WHERE DEPTNO = 30);
EXISTS 연산자
: 서브쿼리에서 실행된 결과가 하나라도 존재 하는지 여부를 확인할 때 사용하는 복수행 연산자이다.
만일 서브쿼리에서 검색된 결과가 하나라도 없으면 메인쿼리에 전달된 값이 FLASE이기 때문에 메인 쿼리가 실행되지 않는다. 검색된 결과가 있으면 값이 TRUE이기 때문에 출력된다.
SELECT ENAME, EMPNO, SAL FROM EMP WHERE EXISTS(SELECT EMPNO FROM EMP WHERE COMM IS NOT NULL);
: 서브쿼리에서 여러 개의 컬럼값을 검색하여 메인쿼리의 조건절과 비교하는 서브쿼리이다. 메인쿼리의 조건절은 서브쿼리의 컬럼과 일대일 매칭이 되어야 한다.
컬럼을 쌍으로 묶는 pairwise방식이 있고 컬럼별로 나누어 비교하고 나중에 AND연산으로 처리하는 unpairwise방식이 있다.
SELECT ENAME, EMPNO, SAL FROM EMP WHERE (EMPNO, SAL) IN
(SELECT EMPNO, MAX(SAL) FROM EMP GROUP BY EMPNO);
--> 서브쿼리를 나눌 수도 있음
SELECT DEPTNO, EMPNO, ENAME, SAL FROM EMP WHERE DEPTNO IN
(SELECT DEPTNO FROM EMP GROUP BY DEPTNO) AND SAL IN
(SELECT MAX(SAL) FROM EMP GROUP BY DEPTNO);
인라인 뷰(in-line view)
: 서브쿼리는 메인쿼리의 WHERE절에 사용된 서브쿼리이다. 하지만 FROM절에도 서브쿼리는 사용할 수 있는 서브쿼리를 '인라인 뷰'라고 부른다.
SELECT select_list
FROM ( 서브쿼리 ) alias
WHERE 조건식;
FROM 절에 서브쿼리를 지정하고 별칭(alias)을 설정한다. 일반적으로 FROM절에는 테이블명이 와야하지만 서브쿼리가 하나의 가상 테이블 형태로 사용될 수 있다.
--> 총 컬럼 수가 11개
SELECT E.DEPTNO, SUM(SAL), AVG(SAL), COUNT(*) FROM EMP E, dept D WHERE e.deptno = D.DEPTNO GROUP BY E.DEPTNO ORDER BY 1;
--> 총 컬럼 수가 7개
SELECT * FROM (SELECT DEPTNO, SUM(SAL), AVG(SAL), COUNT(*) FROM EMP GROUP BY DEPTNO) E, DEPT D WHERE E.DEPTNO = D.DEPTNO ORDER BY 1;
--> 훨씬 적은 수의 데이터로 조인에 참여할 수 있다.
SELECT EMPNO, ENAME, HIREDATE FROM EMP WHERE HIREDATE < (SELECT HIREDATE FROM EMP WHERE ENAME = 'MILLER');
-- 3가지 방법
SELECT EMPNO, ENAME, DEPTNO, SAL FROM EMP WHERE SAL IN (SELECT MAX(SAL) FROM EMP GROUP BY DEPTNO);
SELECT EMPNO, ENAME, DEPTNO, SAL FROM EMP WHERE (DEPTNO, SAL) IN (SELECT DEPTNO, MAX(SAL) FROM EMP GROUP BY DEPTNO);
SELECT EMPNO, ENAME, DEPTNO, SAL FROM EMP WHERE DEPTNO IN (SELECT DEPTNO FROM EMP GROUP BY DEPTNO) AND SAL IN(SELECT MAX(SAL) FROM EMP GROUP BY DEPTNO);
SELECT ENAME, GRADE FROM EMP E JOIN SALGRADE S ON E.SAL BETWEEN S.LOSAL AND S.HISAL WHERE GRADE = (SELECT GRADE FROM EMP E JOIN SALGRADE S ON E.SAL BETWEEN LOSAL AND HISAL WHERE ENAME = 'SMITH');