-
[데이터베이스] SQL 서브 쿼리의 유형 ( IN, NOT IN, EXISTS )데이터베이스와 SQL 2023. 1. 29. 17:49
서브 쿼리는 하나의 SQL문에 포함되는 또 다른 SQL 문으로, 중첩 서브쿼리와 상관 서브 쿼리로 분류 할 수 있다.
중첩 서브쿼리는 단독 실행 가능한 형태이며, 상관 서브쿼리는 외부 테이블 열 참조가 필요한 형태이다.
서브쿼리는 메인 쿼리의 열을 모두 사용할 수 있지만, 메인 쿼리는 서브 쿼리의 칼럼을 사용할 수 없다.
중첩 서브쿼리는 SELECT절의 비교 연산자에서 많이 사용한다.
SELECT ProductID , UnitPrice , AvgPrice = (SELECT UnitPrice FROM dbo.[Order Details]) -- 다중 행 반환 FROM dbo.[Order Details] As od WHERE OrderID <= 10250;
위 쿼리 예시에서 SELECT UnitPrice FROM dbo.[Order Details] 절은 다중 행을 반환하게 되는데, 이 때 SELECT 절에 위치할 경우 값 반환이 불가능하다. 즉, 반드시 하나의 값만 반환이 가능해야 한다.
또한 IN (), NOT IN () 과 함께 사용할 수 있다.
IN은 비교 연산자 (=) 와 논리 연산자 (OR) 을 결합한 연산자이다. IN 절에 중복값이 존재할 때 자동으로 중복값이 제거 되는 암시적 Distinct 의 의미를 내포한다. NULL 값이 있을 경우, IS NULL과 IS NOT NULL 만 사용 가능하므로 자동으로 제거 된다.
-- 집계 SELECT c.CompanyName FROM dbo.Customers AS c WHERE CustomerID IN ( SELECT CustomerID FROM dbo.Orders AS o GROUP BY o.CustomerID HAVING COUNT(*) > 20 );
NOT IN ()은 비교 연산자 (<>)와 논리 연산자 (AND)와 결합한 연산자이다. 따라서 NULL 값이 있을 경우 정합성 문제가 발생 할 수 있기 때문에 NULL 값이 참조되지 않도록 주의 해야 한다.
SELECT Region, * FROM dbo.Customers WHERE Region NOT IN ('SP', 'WA') -- SP와 WA 가 아닌 경우만 추출 ;
만약 NULL 값이 존재할 경우 어떻게 될까?
SELECT 'OK' WHERE '메로나' NOT IN ('브라보콘', '쌍쌍바', NULL) -- 왜 다른가? 어떻게 바뀌는가? SELECT 'OK' WHERE '메로나' <> '브라보콘' -- T or F? AND '메로나' <> '쌍쌍바' AND '메로나' <> NULL -- T or F?
위 쿼리를 실행하면 OK 가 출력 되어야 할 것 같지만 실제 실행을 해 보면 아무것도 출력 되지 않는다.
NULL과 비교를 하는 과정에서 unkwon이 되기 때문이다.
상관 서브 쿼리의 경우에는 SELECT 절, WHERE 조건, HAVING 조건, APPLY , EXISTS연산자와 사용하며, 단독으로 실행이 불가능하다.
SELECT CustomerID , CompanyName = (SELECT CompanyName FROM dbo.Customers AS c WHERE c.CustomerID = o.CustomerID) -- 서브쿼리 내 SELECT 만 실행 불가 , Freight FROM dbo.Orders AS o WHERE o.OrderDate >= DATEADD(dd, -7, '19980510'); -- 집계값 결합 SELECT CustomerID , Freight , AvgFreight = ( SELECT AVG(Freight) FROM dbo.Orders AS a WHERE a.CustomerID = o.CustomerID ) FROM dbo.Orders AS o WHERE o.OrderDate >= DATEADD(dd, -7, '19980510');
EXIST는 부분 검색이 가능한 연산자로, 조건을 만족하는 첫 번째 행을 찾게 되면 더 이상 검색을 하지 않는다.
SELECT c.CompanyName FROM dbo.Customers AS c WHERE c.Country = 'Sweden' AND EXISTS (SELECT 1 FROM dbo.Orders AS o WHERE o.CustomerID = c.CustomerID AND o.EmployeeID IN (2, 3, 4));
EXISTS 절은 다음과 같이 IN을 사용할 수 있다. 하지만 EXISTS는 단독으로 사용 가능하지만, IN의 경우에는 단독으로 사용이 불가능하여 아래와 같은 수정이 필요하다.
SELECT c.CompanyName FROM dbo.Customers AS c WHERE c.Country = 'Sweden' AND c.CustomerID IN (SELECT o.CustomerID FROM dbo.Orders AS o WHERE o.CustomerID = c.CustomerID AND o.EmployeeID IN (2, 3, 4));
내부 쿼리에 없는 외부 테이블 열 참조 시, Insert / Update / Delete와 결합 되는 경우 주의 해야 한다.
반응형'데이터베이스와 SQL' 카테고리의 다른 글
[데이터베이스] SQL 집합 연산자 (intersect, union, except) (1) 2023.01.23 [데이터베이스] MSSQL 조인 방법, inner join과 outer join 차이 (0) 2023.01.23 동적 SQL, EXEC() 와 sp_executesql (0) 2023.01.07 [데이터 베이스] MSSQL 임시테이블과 테이블 변수 (0) 2023.01.07 [데이터 베이스] MSSQL SEQUENCE (시퀀스) 개체 생성 및 사용 (1) 2022.12.17