Education/신한투자증권 프로 디지털 아카데미

SQL 고급자 되어보기 ⁉️

마이캣호두 2025. 8. 10. 15:42
반응형

 

 

 

3. SQL 고급

 

1. 서브쿼리

 

2) 서브쿼리 분류

실무에서 가장 많이 사용하는 건 위치에 따른 분류라고 한다

스칼라 서브쿼리는 select 절에서 컬럼 대용으로, 인라인 뷰는 from 절에서 테이블 대용, 중첩 서브쿼리는 where, having 조건절에서 쓰인다

 

 

3) 연관 여부에 따른 분류 > 비연관 서브쿼리, 연관 서브쿼리

비연관 서브쿼리는 쿼리 자체로 실행될 수 있고, 메인쿼리와 서브쿼리 간 상호작용이 없다

 

연관 서브쿼리 판별법

  • 서브쿼리 안에서 부모 쿼리의 컬럼을 참조하면 연관 서브쿼리다 = 부모에 있는 컬럼이 서브 쿼리에도 있는 것
  • 이때 서브쿼리를 단독 실행하면 E1과 같은 부모 컬럼이 정의되지 않았다는 에러가 발생한다

특징

  • 부모 행마다 서브쿼리가 반복 실행되므로, 비연관 서브쿼리보다 실행 부담이 크다
  • 이번 경우는 연관 서브쿼리이면서, 쿼리 안에 또 다른 쿼리가 들어 있는 중첩 서브쿼리 구조다

 

 

4) 위치에 따른 분류 > 스칼라 서브쿼리, 인라인 뷰, 중첩 서브쿼리

 

스칼라 서브쿼리는 원하는 값 하나를 가져올 때 주로 사용한다

메인 쿼리의 컬럼을 참조하고 있으므로, 이번 경우는 연관 서브쿼리다

연관 서브쿼리는 메인 쿼리가 실행되면서 각 행마다 서브쿼리가 함께 실행된다

스칼라 서브쿼리는 컬럼 위치에서 사용되므로, 반환 결과가 반드시 단일 컬럼, 단일 행이어야 한다 - 그렇지 않으면 다중 행/다중 컬럼 오류가 발생한다

 

인라인 뷰는 테이블처럼 사용하고 싶을 때 사용한다

서브쿼리 결과를 마치 테이블처럼 사용하기 위해 FROM 절에 넣은 서브쿼리이기 때문에 반드시 alias 를 붙여서 사용한다

 

Q. 왜 굳이 이렇게 사용하지?

GROUP BY로 데이터를 먼저 줄인 뒤 SELECT, JOIN을 하기 때문에, 원본 테이블보다 행 수가 줄어들어 JOIN 이 훨씬 가벼워진다

 

서브쿼리를 단독으로 실행해도 동작하므로, 비연관 서브쿼리이면서 인라인 뷰

 

 

 

 

 

중첩 서브쿼리는 WHERE 절에서 조건을 주기 위해 사용하는 서브쿼리다

이 코드와 같이, department_name만 알고 있을 때 그에 해당하는 department_id를 서브쿼리로 가져와 필터링할 수 있다

 

주의할 점은 서브쿼리 결과가 여러 행이 나오는데 = 연산자를 사용하면 단일 행 서브쿼리 오류가 발생한다, 이런 경우에는 = 대신 IN을 사용해 여러 값 비교가 가능하도록 해야 한다

 

 

5) 반환값 유형에 다른 분류 > 단일 행 서브쿼리, 다중 열 서브쿼리

 

단일행 서브 쿼리는 값이 하나만 리턴되기 때문에 = 를 사용할 수 있다

 

 

IN 연산자는 컬럼이 2개 이상이어도 사용할 수 있는데, 단, 비교 대상 컬럼의 개수와 서브쿼리 반환 컬럼 개수가 같아야 한다

 

쿼리를 실행하면 DBMS는 문법·권한 오류를 먼저 확인한 뒤, 옵티마이저가 실행 계획을 만든다

옵티마이저는 같은 결과를 더 빠르게 낼 수 있도록 쿼리를 내부적으로 변환한다 - 우리가 코드를 작성해도 FROM 절이나 서브쿼리 작성 순서 그대로 실행되지 않고, 데이터를 가장 빠르게 가져올 수 있는 순서로 바꿔서 실행한다

따라서 서브쿼리를 썼다고 해서 무조건 느려지는 것은 아니며, 실행 계획에 따라 성능이 결정된다

 

 

2. 실습

 

1) SQL 작성

 

SELECT NAME
FROM CUSTOMERS
WHERE CUSTOMER_ID IN (
    SELECT CUSTOMER_ID
    FROM LOANS
    WHERE BRANCH_ID IN (
        SELECT BRANCH_ID
        FROM BRANCHES
        WHERE LOCATION = 'Busan'
    )
);

-- 방법 2. 조인을 해도 됨
SELECT NAME
FROM CUSTOMERS
WHERE CUSTOMER_ID IN (
    SELECT CUSTOMER_ID
    FROM LOANS l
   	JOIN BRANCHES b ON l.BRANCH_ID = b.BRANCH_ID
    WHERE b.LOCATION = 'Busan'
    )
);

SELECT *
FROM TRANSACTIONS
WHERE ACCOUNT_ID IN (
    SELECT ACCOUNT_ID
    FROM ACCOUNTS
    WHERE CUSTOMER_ID = 100
);

SELECT *
FROM ACCOUNTS
WHERE BALANCE = (
    SELECT MAX(BALANCE)
    FROM ACCOUNTS a
    WHERE CUSTOMER_ID = a.CUSTOMER_ID
);

 

 

 

3. UNION & UNION ALL

 

1) UNION & UNION ALL

 

UNION 은 SELECT 결과를 합친 뒤 중복을 제거

UNION ALL 은 두 SELECT 결과를 단순히 이어 붙여서 중복 포함 모든 데이터 출력

별도의 중복 제거·정렬 과정이 없으므로 UNION ALL 이 더 빠르다

 

 

ORDER BY는 전체 결과 집합에 적용되므로, 맨 마지막 SELECT 뒤에만 쓸 수 있다

alias 는 첫 번째 SELECT 절에서 지정하면 전체 결과에서 그대로 사용할 수 있다

 

 

 

4. 실습

 

1) SQL 작성

SELECT NAME FROM EMPLOYEES WHERE NAME LIKE '%55%'
UNION ALL
SELECT NAME FROM CUSTOMERS WHERE NAME LIKE '%55%';

SELECT CUSTOMER_ID, BALANCE, 'ACCOUNT' AS TYPE FROM ACCOUNTS WHERE BALANCE >= 90000
UNION ALL
SELECT CUSTOMER_ID, AMOUNT, 'LOAN' AS TYPE FROM LOANS WHERE AMOUNT >= 90000;

SELECT DISTINCT CUSTOMER_ID FROM LOANS WHERE LOAN_DATE >= CURRENT_DATE() - INTERVAL 1 MONTH
UNION
SELECT DISTINCT CUSTOMER_ID FROM ACCOUNTS WHERE ACCOUNT_ID IN (
	SELECT ACCOUNT_ID FROM TRANSACTIONS WHERE TRANSACTION_DATE >= CURRENT_DATE() - INTERVAL 1 MONTH
);

 

반응형