티끌모아 태산

⭐️SQL 데이터 조회: subquery 본문

CS 지식/데이터베이스

⭐️SQL 데이터 조회: subquery

goldpig 2023. 9. 14. 23:31
728x90

이번시간에는 SQL에서 subquery를 통해 다양한 조건으로 데이터를 조회하는 방법에 대해서 배워 subquery와 관련된 대표적으로 중요한 기본기들을 익혀보겠습니다.

subquery

- ID가 14인 임직원보다 생일이 빠른 임직원의 ID, 이름, 생일을 알고싶다.-> employee table 참조

SELECT birth_date FROM employee WHERE id = 14;

우선, ID가 14인 임직원의 생일을 파악한다. -> 예를들어 result: 1992-08-04 라 했을 때, 다음과 같이 작성하면 된다.

SELECT id, name, birth_date FROM employee WHERE birth_date < 1992-08-04;

❗️이때, SELECT 문을 두 번 작성하게 되는데, 이를 한번에 처리할 수 있을까? 두 번째 SELECT문의 1992-08-04는 결국 첫번 째 SELECT문의 결과값이기 때문에 첫번 째 SELECT문을 두번 째 SELECT문에 넣어보자 -> subquery!

SELECT id, name, birth_date FROM employee WHERE birth_date < (
						SELECT birth_date FROM employee WHERE id = 14
            );

위 코드에서 "SELECT birth_date FROM employee WHERE id = 14;" 이게 subquery가 된다. 그리고 이 서브 쿼리를 포함하는 "SELECT id, name, birth_date FROM employee WHERE birth_date < 1992-08-04;" 이 코드를 outer query 즉 메인 쿼리라고 부른다.

출처:https://www.youtube.com/watch?v=lwmwlA2WhFc&list=PLcXyemr8ZeoREWGhhZi5FZs6cvymjIBVe&index=6, 쉬운코드
출처:https://www.youtube.com/watch?v=lwmwlA2WhFc&list=PLcXyemr8ZeoREWGhhZi5FZs6cvymjIBVe&index=6, 쉬운코드

- ID가 1인 임직원과 같은 부서 같은 성별인 임직원들의 ID와 이름과 직군을 알고 싶다.-> employee table 참조

SELECT id, name, position FROM employee WHERE (dept_id, sex) = (
	SELECT dept_id, sex FROM employee WHERE id = 1;
);

- ID가 5인 임직권과 같은 프로젝트에 참여한 임직원들의 ID를 알고 싶다. 이때, 결과 테이블에 중복된 튜플을 제외하고 싶다. -> works_on table 참조

SELECT proj_id FROM works_on WHERE empl_id = 5;

이렇게 id 가 5인 임직원이 참여한 프로젝트의 id를 먼저 찾는다. 그리고 그 임직원과 함께 참여한 임직원들의 id를 찾는다. 결과가 2001, 2002라 할 때,

SELECT DISTINCT empl_id FROM works_on WHERE empl_id != 5 AND (proj_id = 2001 OR
	proj_id = 2002
);

이때, 2001과  2002 모두 참여한 사람들도 포함하게 되는 경우 중복이 발생하기 때문에 DISTINCT를 사용하였습니다.

출처:https://www.youtube.com/watch?v=lwmwlA2WhFc&list=PLcXyemr8ZeoREWGhhZi5FZs6cvymjIBVe&index=6, 쉬운코드

코드를 더 간단 명료하게 작성하면 다음과 같다. 

SELECT DISTINCT empl_id FROM works_on WHERE empl_id != 5 AND proj_id IN (
	SELECT proj_id FROM works_on WHERE empl_id = 5
);

출처:https://www.youtube.com/watch?v=lwmwlA2WhFc&list=PLcXyemr8ZeoREWGhhZi5FZs6cvymjIBVe&index=6, 쉬운코드
출처:https://www.youtube.com/watch?v=lwmwlA2WhFc&list=PLcXyemr8ZeoREWGhhZi5FZs6cvymjIBVe&index=6, 쉬운코드
출처:https://www.youtube.com/watch?v=lwmwlA2WhFc&list=PLcXyemr8ZeoREWGhhZi5FZs6cvymjIBVe&index=6, 쉬운코드
출처:https://www.youtube.com/watch?v=lwmwlA2WhFc&list=PLcXyemr8ZeoREWGhhZi5FZs6cvymjIBVe&index=6, 쉬운코드
출처:https://www.youtube.com/watch?v=lwmwlA2WhFc&list=PLcXyemr8ZeoREWGhhZi5FZs6cvymjIBVe&index=6, 쉬운코드

여기서, SET은 중복을 허용하지 않고 multiset은 중복을 허용한다.

출처:https://www.youtube.com/watch?v=lwmwlA2WhFc&list=PLcXyemr8ZeoREWGhhZi5FZs6cvymjIBVe&index=6, 쉬운코드

SELECT DISTINCT empl_id FROM works_on WHERE empl_id != 5 AND proj_id IN (
	SELECT proj_id FROM works_on WHERE empl_id = 5
);

이말은 "SELECT proj_id FROM works_on WHERE empl_id = 5" 여기서 empl_id는 메인쿼리의 works_on이 아닌 서브쿼리의 works_on 테이블을 참조하고, 메인 쿼리에서 eml_id와 proj_id는 메인쿼리의 works_on 테이블을 참조한다는 뜻이다.

💡만약 여기서 추가로 임직원의 id뿐만 아니라 이름도 알고 싶으면 어떻게 해야할까? -> employee, project tables 참조

SELECT id, name FROM employee WHERE id IN (
				SELECT DISTINCT empl_id FROM works_on 
                WHERE empl_id != 5 AND proj_id IN (
                	SELECT proj_id FROM works_on WHERE empl_id = 5)
);

출처:https://www.youtube.com/watch?v=lwmwlA2WhFc&list=PLcXyemr8ZeoREWGhhZi5FZs6cvymjIBVe&index=6, 쉬운코드

- ID가 7 혹은 12인 임직원이 참여한 프로젝트의 ID와 이름을 알고 싶다.-> project, works_on tables 참조하고 IN과 EXISTS 두 가지 방식으로 모두 풀어보기

SELECT P.id, P.name FROM project (AS) P 
	WHERE EXISTS (SELECT * FROM works_on W 
    			WHERE W.proj_id = P.id AND W.empl_id IN (7, 12)
                );

EXISTS -> 원하는 정보를 조회해서 있으면 TRUE. 

출처:https://www.youtube.com/watch?v=lwmwlA2WhFc&list=PLcXyemr8ZeoREWGhhZi5FZs6cvymjIBVe&index=6, 쉬운코드
출처:https://www.youtube.com/watch?v=lwmwlA2WhFc&list=PLcXyemr8ZeoREWGhhZi5FZs6cvymjIBVe&index=6, 쉬운코드

EXIST 와 IN 을 서로 바꿔가면서 사용할 수 있습니다!

출처:https://www.youtube.com/watch?v=lwmwlA2WhFc&list=PLcXyemr8ZeoREWGhhZi5FZs6cvymjIBVe&index=6, 쉬운코드

- 2000년대생이 없는 부서의 ID와 이름을 알고 싶다. -> department, employee tables 참조, NOT EXIST, NOT IN 두가지 방식으로 모두 풀어보기

SELECT D.id, D.name FROM department D WHERE NOT EXIST (
				SELECT * FROM employee E WHERE E.dept_id = D.id AND
                E.birth_date >= '2000-01-01'
);

출처:https://www.youtube.com/watch?v=lwmwlA2WhFc&list=PLcXyemr8ZeoREWGhhZi5FZs6cvymjIBVe&index=6, 쉬운코드

이 코드를 다시 NOT IN 으로 바꿔보자.

출처:https://www.youtube.com/watch?v=lwmwlA2WhFc&list=PLcXyemr8ZeoREWGhhZi5FZs6cvymjIBVe&index=6, 쉬운코드

- 리더보다 높은 연봉을 받는 부서원을 가진 리더의 ID와 이름과 연봉을 알고 싶다. -> department, employee tables 참조, ANY

SELECT E.id, E.name, E.salary FROM department D, employee E 
WHERE D.leader_id = E.id AND E.salary < ANY (
	SELECT salary FROM employee
    WHERE id != D.leader_id AND dept_id = E.dept_id
);

출처:https://www.youtube.com/watch?v=lwmwlA2WhFc&list=PLcXyemr8ZeoREWGhhZi5FZs6cvymjIBVe&index=6, 쉬운코드

💡만약 리더보다 높은 연봉을 받는 부서원을 가진 리더의 ID와 이름과 연봉과 해당 부서 최고 연봉을 알고 싶다.

SELECT E.id, E.name, E.salary, (
    SELECT max(salary)
    FROM employee
    WHERE dept_id = E.dept_id -- 리더와 같은 부서의 임직원을 의미
) AS dept_max_salary -- 결과를 dept_max_salary라고 별칭을 지어줌.

FROM department D, employee E WHERE D.leader_id = E.id AND E.salary < ANY (
	SELECT salary FROM employee WHERE id != D.leader_id AND dept_id = E.dept_id
)

이 예제를 통해 서브 쿼리가 SELECT에도 속할 수 있음을 보여준다.

출처:https://www.youtube.com/watch?v=lwmwlA2WhFc&list=PLcXyemr8ZeoREWGhhZi5FZs6cvymjIBVe&index=6, 쉬운코드

- ID가 13인 임직원과 한번도 같은 프로젝트에 참여하지 못한 임직원들의 ID, 이름, 직군을 알고 싶다. 이때, 중복된 튜플은 제거한다-> ALL, employee, works_on tables 참조

SELECT DISTINCT E.id, E.name, E.position 
FROM employee E, works_on W
WHERE E.id = W.empl_id AND W.proj_id != ALL (
        SELECT proj_id
        FROM works_on
        WHERE empl_id = 13
        );

출처:https://www.youtube.com/watch?v=lwmwlA2WhFc&list=PLcXyemr8ZeoREWGhhZi5FZs6cvymjIBVe&index=6, 쉬운코드
출처:https://www.youtube.com/watch?v=lwmwlA2WhFc&list=PLcXyemr8ZeoREWGhhZi5FZs6cvymjIBVe&index=6, 쉬운코드

728x90

'CS 지식 > 데이터베이스' 카테고리의 다른 글

SQL로 데이터 조회하기, NULL  (0) 2023.09.16
SQL 데이터 조회  (0) 2023.09.10
⭐️SQL을 통한 데이터 추가, 수정, 삭제  (1) 2023.09.08