[sql] JOIN, APPLY 연산자 비교와 사용처 (CROSS APPLY, OUTER APPLY)

TNT·2026년 4월 26일

mssql

목록 보기
8/9

SQL 쿼리를 작성하다 보면 일반적인 JOIN만으로는 해결하기 어려운 복잡한 상황에 맞닥뜨립니다.
예를 들어 사용자별로 최근 3개의 주문 데이터만 가져오고 싶을 때 같은 경우
join으로 하자니 log 테이블에 존재 하는 걸 왼쪽에 두고 전부 set 해서 연결 하고 거기에서 다시 최근 3개를 뽑기가 어렵습니다.
이때 쓰는 것이 바로 APPLY 연산자입니다.

오늘은 APPLY의 개념과 JOIN과의 차이점, 그리고 어떤 상황에서 APPLY를 써야 하는지 알아보자

1. APPLY 연산자

APPLY 연산자는 왼쪽 테이블의 각 행에 대해 오른쪽의 테이블 반환 함수나 서브쿼리를 적용할 때 사용합니다.

종류

CROSS APPLY: INNER JOIN과 유사합니다. 오른쪽 결과가 없으면 왼쪽 행도 출력되지 않습니다.

OUTER APPLY: LEFT JOIN과 유사합니다. 오른쪽 결과가 없어도 왼쪽 행은 유지되며 빈 값은 NULL로 채워집니다.

2. JOIN vs APPLY: 결정적 차이점

가장 큰 차이는 오른쪽 항이 왼쪽 항의 데이터를 참조 할수 있는지 입니다.

사례 1: 사용자별 최근 N개 데이터 가져오기

실무에서 가장 많이 쓰이는 패턴입니다.
모든 고객별로 가장 최근에 주문한 2건씩만 보여달라는 요청이 올 때 JOIN은 한계가 있습니다.
JOIN 사용 시: ROW_NUMBER를 쓰고 번호를 부여 한 이후에 바깥에서 한 번 더 감싸야 해서 복잡합니다.

-- JOIN + 윈도우 함수 방식
SELECT CustomerName, OrderID, OrderDate
FROM (
    SELECT C.CustomerName, O.OrderID, O.OrderDate,
           ROW_NUMBER() OVER(PARTITION BY C.CustomerID ORDER BY O.OrderDate DESC) as rn
    FROM Customers C
    INNER JOIN Orders O ON C.CustomerID = O.CustomerID
) AS T
WHERE rn <= 2; -- 순위가 2위 이내인 것만 필터링

APPLY 사용 시: 쿼리가 훨씬 직관적입니다.

-- CROSS APPLY 방식
SELECT C.CustomerName, O.OrderID, O.OrderDate
FROM Customers C
CROSS APPLY (
    SELECT TOP 2 *
    FROM Orders O
    WHERE O.CustomerID = C.CustomerID -- 왼쪽 테이블 C의 ID를 직접 참조!
    ORDER BY O.OrderDate DESC
) O;

사례 2: 계산된 컬럼 재사용하기

상품 가격에 부가세를 더한 값을 구하고 그 값을 기준으로 또 다른 계산을 해야 할 때 join에서는 다시 계산해야하지만

JOIN 사용시: 중복 계산
일반적인 SELECT문에서는 별칭(Alias)을 바로 다음 컬럼 계산에 쓸 수 없습니다.
그래서 똑같은 계산식을 계속 반복해서 써야 합니다.

SELECT 
    Price,
    Price * 1.1 AS PriceWithTax,
    (Price * 1.1) * 0.1 AS DiscountAmount -- PriceWithTax를 못 써서 또 계산함
FROM Products;

APPLY 방식: 변수처럼 활용

SELECT 
    P.Price, 
    A.PriceWithTax, 
    A.PriceWithTax * 0.1 AS DiscountAmount
FROM Products P
CROSS APPLY (
    SELECT P.Price * 1.1 AS PriceWithTax -- 여기서 계산하고 위에서 써먹음
) A;

이경에는 간단한거는 사실 그냥 join써도 뭐 괜찮은거같긴한경우인데 복잡해지거 쓰는게 많아질경우 정도에만 사용해도 된다.

사례 3: 테이블 반환 함수 호출

사용자 ID를 넣으면 그 사람의 최근 로그 기록을 테이블로 반환하는 함수가 있을 때

SELECT U.UserName, L.*
FROM Users U
CROSS APPLY dbo.fn_GetUserLogs(U.UserID) L; -- 각 유저의 ID를 함수에 전달

이경우에는 join은 바로 연결 못하는경우이다 그냥 apply사용을 해야한다.

결론

JOIN은 두 집합을 옆으로 붙이는 것이고 APPLY는 왼쪽의 각 행을 위해 오른쪽 기능을 매번 실행해 주는 것이다.

상황추천 연산자이유
단순히 두 테이블을 합칠 때JOIN표준 SQL이며 가장 빠르고 기본적임
그룹별 TOP N을 구할 때APPLY윈도우 함수보다 직관적이고 관리가 편함
함수에 파라미터를 넘길 때APPLYJOIN으로는 구현 자체가 불가능함
계산식이 너무 복잡할 때APPLY서브쿼리 내에서 계산 후 별칭으로 재사용 가능
profile
개발

0개의 댓글