-
(2주차 9일) SQL 함수, 조인, 서브쿼리수업 내용 정리 2024. 5. 21. 17:31
MariaDB
> 조인(JOIN)과 UNION 연산자
- 외부 조인(OUTER JOIN)
- 조건에 만족되지 않는 행까지 조회하기 위해서 사용되는 조인
- LEFT JOIN / RIGHT JOIN: 왼쪽 / 오른쪽 테이블의 데이터를 모두 조회
* where문에서는 NULL <> 1이 true로 평가되지 않으므로 where문의 결과값에서 필터링됨
-- LEFT JOIN / RIGHT JOIN: 왼쪽 / 오른쪽 테이블의 데이터는 모두 조회함 -- 'OUTER' 생략 가능 -- where문에서는 NULL <> 1이 true로 평가되지 않으므로 where문의 결과값에서 필터링됨 SELECT emp_id, b.dept_title, dept_code, salary FROM employee a LEFT OUTER JOIN department b ON a.dept_code = b.dept_id ORDER BY a.dept_code; SELECT emp_id, b.dept_title, dept_code, salary FROM employee a RIGHT JOIN department b ON a.dept_code = b.dept_id ORDER BY a.dept_code;
- 상호 조인(CROSS JOIN): 한쪽 테이블의 모든 행들과 다른 쪽 테이블의 모든 행을 조인
-- 데이터가 기하급수적으로 늘어나 과부하 위험이 있음 -- 23개 행(employee) * 9개 행(department) 조합 출력 SELECT emp_name, b.dept_title FROM employee a CROSS JOIN department b ORDER BY emp_name; -- 11개 행(usertbl) * 12개 행(buytbl) 조합 출력 SELECT * FROM usertbl a CROSS JOIN buytbl b ORDER BY a.userID;
- 자체 조인(SELF JOIN): 동일한 테이블을 가지고 조인하여 데이터를 조회
-- 동일한 테이블으로 조인하여 테이블 내의 인덱스를 활용하여 새로운 데이터 생성 -- employee 테이블의 emp_id, emp_name의 정보를 활용하여 사수명(mananger_name) 생성 SELECT a.emp_id, a.emp_name, a.dept_code, /*a.manager_id,*/ b.emp_id AS manager_id, b.emp_name AS manager_name FROM employee a /*INNER*/ LEFT JOIN employee b ON a.manager_id = b.emp_id;
- UNION: 두 쿼리의 결과를 하나로 결합 -> 중복된 열 삭제, 데이터 정렬하여 출력
UNION ALL: 중복된 열까지 모두 출력
-- 열의 개수, 순서를 맞춰주어야 함 -- UNION: 두 쿼리의 결과를 하나로 연결 -> 중복된 열 삭제, 데이터 정렬하여 출력 SELECT emp_id, emp_name, dept_code, salary FROM employee WHERE dept_code = 'D5' UNION SELECT emp_id, emp_name, dept_code, salary FROM employee WHERE salary > 3000000; -- WHERE 절을 활용하여 동일한 처리 가능 SELECT emp_id, emp_name, dept_code, salary FROM employee WHERE dept_code = 'D5' OR salary > 3000000; -- UNION ALL: 중복된 열까지 모두 출력 SELECT emp_id, emp_name, dept_code, salary FROM employee WHERE dept_code = 'D5' UNION ALL SELECT emp_id, emp_name, dept_code, salary FROM employee WHERE salary > 3000000;
> JOIN 연습 문제
/* * JOIN 연습문제 */ -- 70년대생 이면서 여자이고, 성이 전 씨인 직원들의 -- 직원명, 주민번호, 부서명, 직급명을 조회 SELECT emp_name, emp_no, b.dept_title, c.job_name FROM employee a LEFT JOIN department b ON a.dept_code = b.dept_id LEFT JOIN job c ON a.job_code = c.job_code WHERE LEFT(emp_no, 1) = 7 AND SUBSTRING(emp_no, 8, 1) = 2 AND emp_name LIKE '전%'; -- 각 부서별 평균 급여를 조회하여 부서명, 평균 급여를 조회 -- 단, 부서 배치가 안된 사원들의 평균도 같이 나오게 조회 SELECT IFNULL(b.dept_title, '부서없음') AS dept_title, FLOOR(AVG(salary)) AS avg_salary FROM employee a LEFT JOIN department b ON a.dept_code = b.dept_id GROUP BY dept_code ORDER BY avg_salary; -- 각 부서별 총 급여의 합이 1000만원 이상인 부서명, 급여의 합을 조회 SELECT b.dept_title, SUM(salary) FROM employee a LEFT JOIN department b ON a.dept_code = b.dept_id GROUP BY dept_code HAVING SUM(salary) >= 10000000; -- 이름에 '형'자가 들어있는 직원들의 사번, 직원명, 직급명을 조회 SELECT emp_id, emp_name, b.job_name FROM employee a LEFT JOIN job b ON a.job_code = b.job_code WHERE emp_name LIKE '%형%'; -- 해외영업팀에 근무하는 직원들의 직원명, 직급명, 부서 코드, 부서명을 조회 SELECT emp_name, c.job_name, dept_code, b.dept_title FROM employee a LEFT JOIN department b ON a.dept_code = b.dept_id LEFT JOIN job c ON a.job_code = c.job_code WHERE dept_title LIKE '해외영업%';
> 서브쿼리
- 하나의 SQL문 내에 포함된 다른 SQL문을 서브쿼리라고 함
-- e.g. 노옹철 사원과 같은 부서인 사원을 조회 SELECT emp_name, dept_code FROM employee WHERE dept_code = (SELECT dept_code FROM employee WHERE emp_name = '노옹철'); -- (1) 전 직원의 평균 급여 조회 -- (2) 평균 급여보다 더 많은 급여를 받고 있는 직원들을 조회 -- (3) 위의 2단계를 서브 쿼리를 사용하여 하나의 쿼리문으로 작성 SELECT ROUND(AVG(salary)) FROM employee; SELECT emp_name FROM employee WHERE salary > 3047663; SELECT emp_name, salary FROM employee WHERE salary > (SELECT ROUND(AVG(salary)) FROM employee);
- 서브쿼리 구분: 서브쿼리를 수행한 결과값의 행, 열의 개수에 따라 분류
- 단일행 서브쿼리: 서브쿼리 조회 결과 값의 개수가 1개인 경우
- 다중행 서브쿼리: 서브쿼리 조회 결과 값의 개수가 여러 행인 경우
- 다중열 서브쿼리: 서브쿼리 조회 결과 값은 1개이지만, 여러 열로 나타나는 경우
* 다중열의 경우, 쌍비교 활용
-- #단일행 서브쿼리 -- 노옹철 사원보다 급여가 많은 사원의 사번, 이름, 직급명, 부서명, 급여 조회 SELECT emp_id, emp_name, c.job_name, b.dept_title, salary FROM employee a LEFT JOIN department b ON a.dept_code = b.dept_id LEFT JOIN job c ON a.job_code = c.job_code WHERE salary > (SELECT salary FROM employee WHERE emp_name = '노옹철'); -- #다중행 서브쿼리 -- 각 부서별 최고 급여를 받는 직원의 이름, 직급 코드, 부서 코드, 급여 조회 SELECT emp_name, job_code, dept_code, salary FROM employee WHERE salary IN (SELECT MAX(salary) FROM employee GROUP BY dept_code); -- #다중열 서브쿼리 -- 하이유 사원과 같은 부서 코드, 같은 직급 코드에 해당하는 사원 조회 SELECT emp_name, job_code, dept_code FROM employee WHERE (job_code, dept_code) -- 쌍비교 = (SELECT job_code, dept_code FROM employee WHERE emp_name = '하이유'); -- 쌍비교 옵션 SELECT emp_name, job_code, dept_code FROM employee WHERE (job_code, dept_code) IN (('J5', 'D5'), ('J3', 'D4'));
- 서브쿼리 옵션(연산자): ANY, ALL
-- ANY: 서브쿼리 결과 중 하나라도 조건을 만족하면 true를 반환 SELECT emp_id, emp_name, job_code, salary FROM employee WHERE job_code = 'J6' AND salary > ANY (SELECT salary FROM employee WHERE job_code = 'J5'); -- 과장 직급임에도 차장 직급의 최대 급여보다 많이 받는 직원의 사번, 이름, 직급, 급여 조회 -- ALL: 서브쿼리 결과 모두 조건을 만족하면 true를 반환 SELECT emp_id, emp_name, b.job_name, salary FROM employee a INNER JOIN job b ON a.job_code = b.job_code WHERE b.job_name = '과장' AND salary > ALL (SELECT salary FROM employee WHERE job_code = 'J4');
- 위치에 따른 서브쿼리: SELECT, FROM, WHERE, HAVING, ORDER BY절에 사용할 수 있다.
-- #FROM절에 사용되는 서브쿼리: 인라인 뷰 -- 서브쿼리 수행 결과를 테이블 대신 사용 SELECT * FROM (SELECT emp_id, emp_name, salary, salary * 12 AS 연봉 FROM employee) e; -- employee 테이블에서 급여로 순위를 매겨 출력 SELECT emp_name, salary FROM (SELECT ROW_NUMBER() OVER (ORDER BY salary DESC) AS rankno, emp_name, salary FROM employee LIMIT 10) e WHERE rankno BETWEEN 5 AND 10; -- 각 부서별 최고 급여를 받는 직원의 이름, 직급 코드, 부서 코드, 급여 조회 SELECT emp_name, job_code, dept_code, salary FROM (SELECT emp_name, job_code, dept_code, salary, ROW_NUMBER() OVER(PARTITION BY dept_code ORDER BY salary DESC) AS rankno FROM employee) AS T WHERE rankno = 1; -- #SELECT절에 사용되는 서브쿼리: 스칼라 서브쿼리 -- 직원에 대해 사번, 이름, 부서코드, 구분(사원/사수) 조회 SELECT emp_id, emp_name, dept_code, CASE WHEN emp_id IN (SELECT DISTINCT manager_id FROM employee WHERE manager_id IS NOT NULL) THEN '사수' ELSE '사원' END AS alias FROM employee; -- #WHERE절에 사용되는 서브쿼리 -- 대리 직급임에도 과장 직급의 최소 급여보다 많이 받는 직원의 사번, 이름, 직급, 급여 조회 SELECT emp_id, emp_name, job_code, salary FROM employee WHERE job_code = 'J6' AND salary > (SELECT MIN(salary) FROM employee GROUP BY job_code HAVING job_code = 'J5');
> 서브쿼리 연습문제
-- #다중행, 다중열 연습 문제(쌍비교) -- 박나라 사원과 같은 직급 코드, 같은 사수에 해당하는 사원 조회 SELECT emp_id, emp_name, job_code, manager_id FROM employee WHERE (job_code, manager_id) = (SELECT job_code, manager_id FROM employee WHERE emp_name = '박나라'); -- 각 부서별 최고 급여를 받는 직원의 사번, 이름, 부서 코드, 급여 조회 SELECT emp_id, emp_name, IFNULL(dept_code, '부서없음') AS dept_code, salary FROM employee WHERE (IFNULL(dept_code, '부서없음'), salary) IN (SELECT IFNULL(dept_code, '부서없음'), MAX(salary) AS salary FROM employee GROUP BY dept_code) ORDER BY dept_code; -- 각 부서별 최소 급여를 받는 직원의 사번, 이름, 부서 코드, 급여 조회 SELECT emp_id, emp_name, IFNULL(dept_code, '부서없음') AS dept_code, salary FROM employee WHERE (IFNULL(dept_code, '부서없음'), salary) IN (SELECT IFNULL(dept_code, '부서없음'), MIN(salary) AS salary FROM employee GROUP BY dept_code) ORDER BY dept_code; -- 각 직급별 최소 급여를 받는 직원의 사번, 이름, 직급 코드, 급여 조회 SELECT emp_id, emp_name, job_code, salary FROM employee WHERE (job_code, salary) IN (SELECT job_code, MIN(salary) AS salary FROM employee GROUP BY job_code) ORDER BY job_code;
'수업 내용 정리' 카테고리의 다른 글
(2주차 11일) 테이블 실습 (0) 2024.05.23 (2주차 10일) DB 모델링, erdcloud, 테이블, 뷰 (0) 2024.05.22 (2주차 8일) SQL 함수, 조인, 서브쿼리 (0) 2024.05.20 (1주차 5일) SQL 기본 (0) 2024.05.17 (1주차 4일) MariaDB, SQL 기본 (0) 2024.05.16 - 외부 조인(OUTER JOIN)