[SQL] 서브쿼리

2022. 3. 29. 22:22카테고리 없음

JOIN과의 차이

조인은 조인에 참여하는 모든 테이블이 대등한 관계에 있기 때문에 조인에 참여하는 모든 테이블의 칼럼을 어느 위치에서라도 자유롭게 사용할 수 있다.

그러나 서브쿼리는 메인 쿼리의 칼럼을 모두 사용할 수 있지만, 메인 쿼리는 서브 쿼리의 칼럼을 사용할 수 없다.

질의 결과에 서브 쿼리 칼럼을 표시해야 한다면 조인 방식으로 변환하거나 함수, 스칼라 서브 쿼리 등을 사용해야 한다.

 

SQL 문에서 서브 쿼리 방식을 사용해야 할 때 잘못 판단해 조인 방식을 사용하는 경우가 있다.

예를 들어 결과는 조직레벨이고, 사원 테이블에서 체크해야할 조건이 있다면....

이 때는 조인 방식이 아니라 서브 쿼리 방식을 사용해야 한다.

메인 쿼리로 조직을 사용하고 서브 쿼리로 사원 테이블을 사용하면 결과 집합은 조직레벨이 되기 때문에 원하는 결과가 된다.

 

주의점

1) 서브 쿼리는 괄호로 감싸서 기술한다.

2) 서브 쿼리는 단일 행 또는 복수 행 비교 연산자와 함께 사용 가능하다. 단일 행 비교 연산자는 서브 쿼리의 결과가 반드시 1건 이하여야 하고, 복수행 비교 연산자는 서브 쿼리의 결과 건수와 상관이 없다.

3) 중첩 서브 쿼리 및 스칼라 서브 쿼리에서는 ORDER BY를 사용하지 못한다.

 

 

 

단일 행 서브 쿼리

정남일 선수가 소속된 팀의 선수들에 대한 정보를 표시하는 문제를 서브 쿼리 방식의 SQL 문으로 작성하면 다음과 같다.

SELECT PLAYER_NAME AS 선수명, POSITION AS 포지션, BACK_NO AS 백넘버
FROM PLAYER
WHERE TEAM_ID = (SELECT TEAM_ID
			FROM PLAYER
            WHERE PLAYER_NAME = '정남일')
ORDER BY PLAYER_NAME;

정남일 선수의 소속팀을 알아내는 서브쿼리가 먼저 수행돼 정남일 선수의 소속팀 ID가 반환된다.

메인 쿼리는 서브 쿼리에서 반환된 결과를 이용해서 조건을 만족하는 선수들의 정보를 출력한다.

만약 정남일 선수와 같은 이름을 가진 동명이인이 있었다면 2건 이상의 결과가 반환돼 SQL 문에 오류가 발생한다.

다중 행 서브 쿼리

서브 쿼리의 결과가 2건 이상 반환될 수 있다면 반드시 다중 행 비교 연산자(IN, ALL, ANY, SOME)와 함께 사용해야 한다.

앞서 다중의 행이 반환되면 오류가 발생하는 일을 방지하기 위해 다중 행 비교 연산자로 바꾸어서 SQL 문을 작성하면 다음과 같다.

SELECT PLAYER_NAME AS 선수명, POSITION AS 포지션, BACK_NO AS 백넘버
FROM PLAYER
WHERE TEAM_ID IN (SELECT TEAM_ID
			FROM PLAYER
            WHERE PLAYER_NAME = '정남일')
ORDER BY PLAYER_NAME;

다중 칼럼 서브 쿼리

다중 칼럼 서브 쿼리는 서브 쿼리의 결과로 여러 개의 칼럼이 반환돼 메인 쿼리의 조건과 동시에 비교되는 것을 의미한다.

하지만 SQL Server에서는 지원되지 않는 문법이다.

연관 서브 쿼리

- 서브 쿼리 내에 메인 쿼리 칼럼이 사용된 서브 쿼리

 

ex) 선수 자신이 속한 팀의 평균키보다 작은 선수들의 정보를 출력

SELECT B.TEAM_NAME AS 팀명, A.PLAYER_NAME AS 선수명, A.POSITION AS 포지션,
	A.BACK_NO AS 백넘버, A.HEIGHT AS 키
FROM PLAYER A, TEAM B
WHERE A.HEIGHT < (SELECT AVG(X.HEIGHT)
			FROM PLAYER X
            WHERE X.TEAM_ID = A.TEAM_ID
            GROUP BY X.TEAM_ID)
AND B.TEAM_ID = A.TEAM_ID
ORDER BY 선수명;

예를 들어 가비 선수는 삼성 블루윙즈 팀 소속이므로 삼성 블루윙즈 팀 소속 선수들의 평균 키를 구하고, 가비 선수의 키가 그 평균키보다 작으므로 해당 선수의 정보를 출력한다.

 

EXISTS 서브 쿼리는 항상 연관 서브 쿼리로 사용된다.

또한 EXISTS 서브 쿼리의 특징은 아무리 조건을 만족하는 건이 여러 건이더라도 조건을 만족하는 1건만 찾으면 추가적인 검색을 하지 않는다.

ex) 20120501부터 20120502 사이에 경기가 있는 경기장을 조회하는 SQL문

SELECT A.STADIUM_ID AS ID, A.STADIUM_NAME AS 경기장명
FROM STADIUM A
WHERE EXISTS (SELECT 1
			FROM SCHEDULE X
            WHERE X.STADIUM_ID = A.STADIUM
            AND X.X.SCH_DATE BETWEEN '20120501' AND '20120502');

그 밖의 위치에서 사용하는 서브 쿼리

가. SELECT 절에서 서브 쿼리 사용하기

스칼라 서브 쿼리는 한 행, 한 칼럼만 반환하는 서브 쿼리이다.

스칼라 서브 쿼리는 칼럼을 쓸 수 있는 대부분의 곳에서 사용할 수 있다.

 

나. FROM 절에서 서브 쿼리 사용하기

FROM절에서 사용되는 서브 쿼리를 인라인 뷰라고 한다.

인라인 뷰를 사용하면 서브 쿼리의 결과를 마치 테이블처럼 사용할 수 있다.

 

일반 뷰와의 차이점은?

- 일반 뷰: 데이터베이스에 SELECT 문을 객체로서 저장해 테이블처럼 사용

- 인라인 뷰: 쿼리 내에서 즉시 처리

 

다. HAVING 절에서 서브 쿼리 사용하기

HAVING 절은 집계함수와 함께 사용될 때 그룹핑된 결과에 대해 부가적인 조건을 주기 위해 사용한다.

 

뷰 vs. 테이블

- 테이블: 실제로 데이터를 갖고 있다.

- 뷰: 실제로 데이터를 갖고 있지 않다. 뷰는 단지 뷰 정의만을 갖고 있다.

질의에서 뷰가 사용되면 뷰 정의를 참조해서 DBMS 내부적으로 질의를 재작성해 질의를 수행한다.

 

뷰는 CREATE VIEW 문으로 생성할 수 있다.

뷰를 제거하기 위해서는 DROP VIEW 문을 사용한다.