SQL에서 서브쿼리(Subquery) 기본 개념과 예제

제공

안녕하세요, 여러분! 오늘은 데이터베이스에서 마법처럼 활용되는 SQL 서브쿼리에 대해 함께 알아보는 시간을 가져보려고 해요. 마치 마트료시카 인형처럼 쿼리 안에 또 다른 쿼리가 쏙 들어가 있는 구조, 상상이 되시나요? 이 신기한 서브쿼리를 사용하면 복잡한 데이터 분석도 훨씬 간결하고 효율적으로 할 수 있답니다. 궁금하시죠? 서브쿼리의 종류와 다양한 사용 예시를 통해 여러분의 SQL 실력을 한 단계 업그레이드할 수 있는 기회를 놓치지 마세요! 함께 SQL의 세계를 탐험해 봐요!

 

 

서브쿼리란 무엇인가?

데이터베이스를 다루다 보면, 특정 조건에 맞는 데이터를 추출해야 하는 경우가 정말 많아요. 이때, 메인 쿼리 내에 또 다른 쿼리를 포함시켜 조건을 명시하는 강력한 도구가 있는데, 바로 “서브쿼리(Subquery)“랍니다! 마치 마트료시카 인형처럼 쿼리 안에 쿼리가 들어가 있는 구조라고 생각하시면 돼요.

서브쿼리의 역할

좀 더 자세히 설명드리자면, 서브쿼리는 메인 쿼리(Outer Query)에 필요한 데이터를 제공하기 위해 중첩되어 사용되는 쿼리를 말해요. 마치 탐정이 단서를 찾아 범인을 추적하듯, 서브쿼리는 메인 쿼리의 조건을 만족시키는 값을 찾아 전달해주는 역할을 한답니다.

서브쿼리의 장점

서브쿼리는 SQL의 표준 기능 중 하나로, ANSI SQL 표준을 준수하는 거의 모든 데이터베이스 시스템(MySQL, PostgreSQL, Oracle, SQL Server 등)에서 사용 가능해요. 이 덕분에 한번 익혀두면 다양한 환경에서 활용할 수 있다는 장점이 있죠!

서브쿼리는 단일 값, 여러 값 또는 행 집합을 반환할 수 있으며, SELECT, INSERT, UPDATE, DELETE 문을 포함한 다양한 SQL 문에서 WHERE 절, HAVING 절, FROM 절 등 거의 모든 절에 사용될 수 있어요. 이러한 유연성 덕분에 복잡한 쿼리를 간결하고 효율적으로 작성할 수 있답니다.

서브쿼리 활용 예시

예를 들어, 전체 직원의 평균 연봉보다 높은 연봉을 받는 직원을 찾는다고 가정해 볼게요. 이때 서브쿼리를 사용하면 다음과 같이 쿼리를 작성할 수 있어요.


SELECT employee_name
FROM employees
WHERE salary > (SELECT AVG(salary) FROM employees);

괄호 안의 SELECT AVG(salary) FROM employees 부분이 바로 서브쿼리인데요, 이 서브쿼리는 전체 직원의 평균 연봉을 계산하여 메인 쿼리에 전달해요. 메인 쿼리는 전달받은 평균 연봉보다 높은 연봉을 받는 직원의 이름을 출력하죠.

서브쿼리의 유형

서브쿼리는 크게 두 가지 유형으로 나눌 수 있어요. 바로 단일 행 서브쿼리(Single-row subquery)와 다중 행 서브쿼리(Multi-row subquery)입니다.

  • 단일 행 서브쿼리: 이름에서 알 수 있듯이, 단일 값을 반환하는 서브쿼리에요. 비교 연산자(=, !=, >, <, >=, <=)와 함께 사용되며, 위에서 본 평균 연봉 예시가 바로 단일 행 서브쿼리의 대표적인 예시랍니다.
  • 다중 행 서브쿼리: 여러 개의 값을 반환하는 서브쿼리로, IN, ALL, ANY, SOME과 같은 집합 연산자와 함께 사용돼요. 예를 들어, 특정 부서에 속한 직원들의 이름을 찾을 때 다중 행 서브쿼리를 사용할 수 있죠.

서브쿼리의 장단점 및 주의사항

서브쿼리를 사용하면 복잡한 조건을 효과적으로 처리할 수 있고, 코드의 가독성을 높일 수 있다는 장점이 있어요. 또한, 쿼리의 재사용성을 높여 유지보수를 용이하게 해준답니다.

하지만 서브쿼리를 과도하게 사용하면 쿼리 성능이 저하될 수 있으니 주의해야 해요! 특히, 대규모 데이터베이스에서는 서브쿼리의 남용이 심각한 성능 병목 현상을 초래할 수 있으니, 상황에 따라 조인(JOIN)을 사용하는 것이 더 효율적일 수 있다는 점을 기억해 두세요.

서브쿼리는 SQL의 꽃이라고 불릴 만큼 강력하고 유용한 기능이에요. 다양한 예시를 통해 서브쿼리의 활용법을 익히고, 데이터베이스 활용 능력을 한 단계 업그레이드해 보세요!

 

서브쿼리의 종류

자, 이제 드디어 서브쿼리의 종류에 대해 알아볼 시간이에요! 서브쿼리는 그 쓰임새에 따라 몇 가지 종류로 나눌 수 있는데요, 각각의 특징과 장단점을 잘 이해하는 것이 SQL 마스터로 가는 지름길이랍니다! 마치 RPG 게임에서 스킬 트리를 찍는 것처럼 말이죠!

단일행 서브쿼리 (Single-Row Subquery)

먼저, 가장 기본적인 단일행 서브쿼리 (Single-Row Subquery)부터 시작해 볼게요. 이름에서 짐작할 수 있듯이, 이 녀석은 단 하나의 행만 반환하는 서브쿼리를 말해요. 주로 =, >, <, >=, <=, <> 같은 비교 연산자와 함께 사용되며, 외부 쿼리의 조건을 만족하는 단 하나의 값을 찾아내는 데 특화되어 있어요. 예를 들어, 전체 직원 중에서 ‘홍길동’이라는 직원과 같은 부서에 속한 직원들을 찾고 싶다면, 단일행 서브쿼리를 사용해서 ‘홍길동’의 부서 ID를 먼저 찾고, 그 ID를 이용해 다른 직원들을 검색할 수 있겠죠?

다중행 서브쿼리 (Multi-Row Subquery)

다음으로 소개할 친구는 다중행 서브쿼리 (Multi-Row Subquery)입니다! 이름에서 알 수 있듯이 여러 개의 행을 반환하는 서브쿼리인데요, 다중행 서브쿼리는 IN, ALL, ANY, SOME과 같은 연산자와 함께 사용되며, 여러 개의 값을 비교해야 할 때 유용하게 쓰인답니다. 예를 들어, ‘영업부’ 또는 ‘마케팅부’에 속한 모든 직원의 정보를 가져오고 싶다면, 다중행 서브쿼리를 사용해서 두 부서의 ID를 모두 가져온 후, 그 ID들을 포함하는 직원들을 찾을 수 있어요.

상관 서브쿼리 (Correlated Subquery)

세 번째로 알아볼 서브쿼리는 상관 서브쿼리 (Correlated Subquery)입니다. 이 녀석은 좀 특별한 친구인데요, 외부 쿼리의 각 행에 대해 서브쿼리가 매번 실행되는 독특한 방식으로 동작해요. 상관 서브쿼리는 외부 쿼리의 특정 값을 서브쿼리에서 사용할 수 있기 때문에, 더욱 복잡하고 정교한 조건을 구현할 수 있다는 장점이 있어요. 예를 들어, 각 부서에서 가장 높은 급여를 받는 직원을 찾고 싶다면, 상관 서브쿼리를 사용해서 각 부서의 최고 급여를 계산하고, 그 값과 같은 급여를 받는 직원을 찾을 수 있습니다.

서브쿼리의 위치

이 외에도 서브쿼리는 위치에 따라 SELECT 절, FROM 절, WHERE 절, HAVING 절 등 다양한 곳에 사용될 수 있어요. 각 절에서 어떻게 활용되는지, 그리고 어떤 장단점이 있는지 자세히 알아두면 SQL 실력 향상에 큰 도움이 될 거예요!

서브쿼리 종류 표

종류 설명 사용 연산자
단일행 서브쿼리 한 행만 반환 =, >, <, >=, <=, <>
다중행 서브쿼리 여러 행 반환 IN, ALL, ANY, SOME
상관 서브쿼리 외부 쿼리의 각 행에 대해 실행 외부 쿼리의 컬럼 참조

서브쿼리를 잘 활용하면 복잡한 쿼리를 간결하고 효율적으로 작성할 수 있지만, 과도하게 사용하면 쿼리 성능이 저하될 수 있다는 점도 잊지 마세요! 적재적소에 적절하게 사용하는 것이 중요하답니다! 다음에는 실제 서브쿼리 사용 예시를 통해 더욱 자세하게 알아보도록 할게요.

 

서브쿼리 사용 예시

자, 이제 드디어 서브쿼리가 실제로 어떻게 활용되는지 살펴볼 시간이에요! 두근두근하지 않나요? ^^ 간단한 예시부터 복잡한 예시까지, 차근차근 알아보도록 할게요. ☕ 데이터베이스는 AdventureWorks라는 가상의 회사 데이터베이스를 사용할 거예요. (이 데이터베이스는 Microsoft에서 제공하는 샘플 데이터베이스랍니다!)

1. 평균 주문 금액보다 높은 주문을 한 고객 찾기

음~, 🤔 우리 회사에서 평균 주문 금액보다 많은 돈을 쓴 VIP 고객님들을 찾아야 한다고 가정해 볼게요. 이럴 때 서브쿼리가 아주 유용하게 쓰인답니다!

SELECT CustomerID, OrderDate, TotalDue
FROM Sales.SalesOrderHeader
WHERE TotalDue > (SELECT AVG(TotalDue) FROM Sales.SalesOrderHeader);

괄호 안의 SELECT AVG(TotalDue) FROM Sales.SalesOrderHeader 부분이 바로 서브쿼리에요. 이 서브쿼리는 모든 주문의 평균 금액을 계산하죠. 그리고 메인 쿼리는 이 평균 금액보다 TotalDue (총 주문 금액)가 높은 주문들을 찾아줍니다. 참 쉽죠?! 🎉

2. 특정 제품을 구매한 고객의 정보 조회

이번에는 ‘ProductID’가 707인 제품, 예를 들어 최신형 스마트폰이라고 해볼까요? 📱 이 스마트폰을 구매한 고객님들의 정보를 알고 싶다고 해봅시다.

SELECT c.CustomerID, c.FirstName, c.LastName
FROM Sales.Customer AS c
WHERE c.CustomerID IN (SELECT sod.CustomerID
                      FROM Sales.SalesOrderDetail AS sod
                      WHERE sod.ProductID = 707);

여기서 SELECT sod.CustomerID FROM Sales.SalesOrderDetail AS sod WHERE sod.ProductID = 707 이 부분이 서브쿼리죠! 이 서브쿼리는 ‘ProductID’가 707인 제품을 구매한 고객의 ID를 모두 찾아줍니다. 그리고 메인 쿼리는 이 고객 ID를 이용해서 Customer 테이블에서 고객의 이름과 성 등 자세한 정보를 가져오는 거죠! 참 똑똑하죠? 😊

3. 상위 10% 판매량을 기록한 제품 찾기

자, 이번에는 조금 더 복잡한 예시를 볼까요? 판매량 상위 10%를 차지하는 핫한 🔥 제품들을 찾아보자구요!

SELECT ProductID, SUM(OrderQty) AS TotalQuantitySold
FROM Sales.SalesOrderDetail
GROUP BY ProductID
HAVING SUM(OrderQty) >= (SELECT PERCENTILE_CONT(0.9) WITHIN GROUP (ORDER BY SUM(OrderQty))
                         FROM Sales.SalesOrderDetail
                         GROUP BY ProductID);

이 예시에서는 PERCENTILE_CONT(0.9) 함수를 사용했어요. 이 함수는 90번째 백분위수, 즉 상위 10%에 해당하는 값을 계산해 줍니다. 서브쿼리는 모든 제품의 판매량을 기준으로 상위 10%에 해당하는 판매량 기준값을 계산하고, 메인 쿼리는 이 기준값보다 판매량이 높은 제품들을 찾아주는 거예요! 와우! 🤩

4. 각 부서별 최고 연봉자 찾기

이번엔 각 부서에서 가장 많은 연봉을 받는 직원을 찾아볼까요? 🤔 이것도 서브쿼리를 이용하면 아주 간단하게 해결할 수 있답니다!

SELECT e.EmployeeID, e.DepartmentID, e.Salary
FROM HumanResources.Employee AS e
WHERE (e.DepartmentID, e.Salary) IN (SELECT DepartmentID, MAX(Salary)
                                     FROM HumanResources.Employee
                                     GROUP BY DepartmentID);

이 쿼리에서는 서브쿼리가 각 부서별 최고 연봉을 계산하고, 메인 쿼리는 이 정보를 이용해서 각 부서의 최고 연봉자를 찾아줍니다. 정말 편리하죠? 👍

5. 특정 날짜 이후에 주문한 고객 목록

마지막으로, 특정 날짜 이후에 주문한 고객 목록을 찾는 예시를 볼게요. 예를 들어, 2023년 7월 1일 이후에 주문한 고객들을 찾아봅시다.

SELECT DISTINCT c.CustomerID, c.FirstName, c.LastName
FROM Sales.Customer AS c
INNER JOIN Sales.SalesOrderHeader AS soh ON c.CustomerID = soh.CustomerID
WHERE soh.OrderDate >= '2023-07-01'
AND soh.CustomerID IN (SELECT CustomerID FROM Sales.SalesOrderHeader WHERE OrderDate >= '2023-07-01');

이 쿼리에서 서브쿼리는 2023년 7월 1일 이후에 주문한 고객 ID를 찾고, 메인 쿼리는 이 ID를 사용하여 고객 정보를 가져옵니다. DISTINCT 키워드를 사용하여 중복된 고객 정보가 표시되지 않도록 했어요! 😉

이처럼 서브쿼리는 다양한 상황에서 유용하게 활용될 수 있어요! 여러분도 다양한 예시를 통해 서브쿼리 활용법을 익혀보세요! 화이팅! 💪

 

서브쿼리 사용 시 주의사항

자, 이제 드디어 서브쿼리 사용 시 주의해야 할 점들을 살펴볼 시간이에요! 마치 맛있는 케이크를 먹기 전에 주의사항을 읽는 것처럼 말이죠~? 서브쿼리는 강력한 도구이지만, 잘못 사용하면 쿼리 성능 저하나 예상치 못한 결과를 초래할 수 있어요. 그러니 지금부터 알려드리는 꿀팁들을 잘 기억해 두셨다가 써먹어 보세요!

1. 상관 서브쿼리의 과도한 사용은 지양하기!

상관 서브쿼리는 바깥쪽 쿼리의 각 행에 대해 반복적으로 실행되기 때문에, 데이터 양이 많아지면 쿼리 성능에 악영향을 미칠 수 있어요. 마치 러시아워에 좁은 골목길로 들어선 것처럼 쿼리가 꽉 막히는 상황이 발생할 수 있다는 거죠! 특히 대규모 데이터베이스에서는 상관 서브쿼리 대신 조인(JOIN)을 사용하는 것이 훨씬 효율적일 수 있답니다. 예를 들어 100만 건의 데이터를 처리하는 쿼리에 상관 서브쿼리를 사용하면, 최악의 경우 100만 번의 서브쿼리가 실행될 수도 있어요. 으악, 생각만 해도 아찔하죠?!

2. IN 연산자와 EXISTS 연산자의 적절한 활용

서브쿼리에서 IN 연산자EXISTS 연산자는 자주 사용되는데요, 각각의 특징을 잘 이해하고 상황에 맞게 사용해야 해요. IN 연산자는 서브쿼리 결과 집합에 특정 값이 존재하는지 확인하는 반면, EXISTS 연산자는 서브쿼리 결과 집합이 비어 있지 않은지만 확인해요. 만약 서브쿼리 결과가 NULL 값을 포함할 가능성이 있다면, IN 연산자는 예상치 못한 결과를 반환할 수 있어요. 이럴 때는 EXISTS 연산자를 사용하는 것이 안전하고 효율적이랍니다! 마치 울퉁불퉁한 비포장도로를 달릴 때는 튼튼한 SUV가 필요한 것처럼 말이죠!

3. 다중 컬럼 서브쿼리의 주의 깊은 사용

다중 컬럼 서브쿼리는 여러 개의 컬럼을 반환하는 서브쿼리인데요, 비교 연산자와 함께 사용할 때 주의가 필요해요. 다중 컬럼 서브쿼리는 여러 개의 값을 튜플 형태로 반환하는데, 이 튜플을 단일 값과 직접 비교할 수는 없어요. 마치 사과와 오렌지를 비교하는 것처럼 말이죠?! 다중 컬럼 서브쿼리를 사용할 때는 각 컬럼을 개별적으로 비교하거나, 튜플 전체를 비교하는 방법을 사용해야 한답니다.

4. 서브쿼리의 중첩 레벨 제한

데이터베이스 시스템마다 서브쿼리의 중첩 레벨에 제한이 있을 수 있어요. 너무 깊게 중첩된 서브쿼리는 쿼리의 복잡성을 증가시키고 가독성을 떨어뜨릴 뿐만 아니라, 성능에도 부정적인 영향을 미칠 수 있어요. 마치 100층짜리 건물에서 계단으로 오르내리는 것처럼 힘들고 시간이 오래 걸리는 작업이 될 수 있다는 거죠! 일반적으로 서브쿼리의 중첩 레벨은 3~4단계 이내로 유지하는 것이 좋다고 알려져 있어요.

5. NULL 값 처리에 대한 고려

서브쿼리 결과에 NULL 값이 포함될 가능성이 있다면, NULL 값 처리 방식을 신중하게 고려해야 해요. NULL 값은 비교 연산에서 예상치 못한 결과를 초래할 수 있기 때문이죠. 마치 보물찾기에서 빈 상자를 발견한 것처럼 허탈한 결과를 얻을 수도 있어요! NULL 값을 처리하기 위해 IS NULL, IS NOT NULL, COALESCE, NVL 등의 함수를 적절히 활용하는 것이 중요해요.

6. 코드 가독성 확보를 위한 노력

복잡한 서브쿼리는 코드의 가독성을 떨어뜨리고 유지보수를 어렵게 만들 수 있어요. 마치 미로처럼 복잡한 쿼리를 보면 머리가 지끈거리겠죠?! 서브쿼리를 사용할 때는 적절한 들여쓰기와 주석을 사용하여 코드의 가독성을 높이는 것이 중요해요. 또한, 가능하다면 서브쿼리 대신 조인이나 CTE(Common Table Expression)를 사용하는 것을 고려해 보세요. CTE는 마치 쿼리에 별명을 붙여주는 것처럼, 복잡한 쿼리를 간결하고 이해하기 쉽게 만들어준답니다.

7. 성능 테스트와 최적화

서브쿼리를 사용한 쿼리를 작성한 후에는 반드시 성능 테스트를 진행하고 필요에 따라 최적화 작업을 수행해야 해요. 쿼리 성능 분석 도구를 사용하여 쿼리 실행 계획을 분석하고, 병목 현상이 발생하는 부분을 파악하여 개선해야 한답니다. 마치 자동차 정비처럼 꾸준한 관리와 점검이 필요한 거죠!

자, 이제 서브쿼리 사용 시 주의사항에 대해 꼼꼼하게 살펴봤어요! 이러한 주의사항들을 잘 기억하고 적용한다면, 서브쿼리를 효과적으로 활용하여 더욱 강력하고 효율적인 쿼리를 작성할 수 있을 거예요! 마치 요리 레시피처럼, 주의사항을 잘 지켜야 맛있는 요리가 완성되는 것과 같은 이치랍니다! 이제 여러분은 서브쿼리 마스터가 될 준비가 되었어요! 화이팅!

 

자, 이제 SQL 서브쿼리에 대해 조금 더 알게 되셨나요? 처음엔 어려워 보였을지도 모르지만, 차근차근 살펴보니 생각보다 흥미롭지 않았어요? 마치 숨겨진 보물찾기 같았죠. 서브쿼리를 잘 활용하면 데이터베이스에서 원하는 정보를 쏙쏙 뽑아낼 수 있어요. 마법처럼요! 앞으로 데이터 분석이나 개발을 할 때 오늘 배운 내용이 든든한 도구가 되어줄 거예요. 복잡한 쿼리문을 만나더라도 당황하지 말고, 서브쿼리 활용법을 떠올리면서 멋지게 해결해 보세요. 여러분의 데이터 분석 여정을 응원할게요! 더 궁금한 점이 있다면 언제든지 질문해주세요.

 


코멘트

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다