1. 년,월, 성별 별 상품 구매 회원 수 구하기
https://school.programmers.co.kr/learn/courses/30/lessons/131532?language=oracle
SELECT
EXTRACT(YEAR FROM S.SALES_DATE) AS YEAR,
EXTRACT(MONTH FROM S.SALES_DATE) AS MONTH,
I.GENDER,
COUNT(DISTINCT (S.USER_ID)) AS USERS
FROM ONLINE_SALE S
JOIN USER_INFO I ON S.USER_ID = I.USER_ID
WHERE I.GENDER IS NOT NULL
GROUP BY EXTRACT(YEAR FROM S.SALES_DATE), EXTRACT(MONTH FROM S.SALES_DATE), I.GENDER
ORDER BY YEAR, MONTH, I.GENDER
POINT!
1. 오라클에서 GROUP BY특징
- SELECT 절의 비집계 컬럼(일반 컬)·표현식 → GROUP BY에 반드시 포함
- 집계 함수 결과 → GROUP BY에 넣지 않음
- 그래서 SELECT절에 회원수도 'COUNT(DISTINCT s.user_id)' GROUP BY에 미포함
- 별칭은 GROUP BY에서 못 씀 → 표현식을 그대로 써야 함
2. DISTINCT의 중요성
문제에서는 구매한 회원수를 집계 하라고 했습니다. 여기서 포인트는 회원수인데요
회원수는 사람을 세는 겁니다. 그래서 DISTINCT를 적용해야하죠
만약 적용하지 않았다면 한 사람이 여러번 구매한 것도 포함이 되기 때문에 그것은 구매 건수로 집계되는 겁니다.
그래서 그 달의 구매한 회원수를 구하기 위해서는 DISTINCT를 적용해야하는 거죠
2. 우유와 요거트가 담긴 장바구니
https://school.programmers.co.kr/learn/courses/30/lessons/62284?language=oracle
SELECT CART_ID
FROM (
SELECT
CART_ID,
LISTAGG(NAME, ',') WITHIN GROUP(ORDER BY NAME) AS NAME
FROM CART_PRODUCTS
GROUP BY CART_ID
)
WHERE NAME LIKE '%Milk%'
AND NAME LIKE '%Yogurt%'
ORDER BY CART_ID;
다 풀이 : LIKE 대신 HAVING을 쓰면 더 깔끔하다
SELECT CART_ID
FROM CART_PRODUCTS
GROUP BY CART_ID
HAVING SUM(CASE WHEN NAME = 'Milk' THEN 1 ELSE 0 END) > 0
AND SUM(CASE WHEN NAME = 'Yogurt' THEN 1 ELSE 0 END) > 0
ORDER BY CART_ID;
- CART_ID별로 Milk와 Yogurt가 동시에 들어간 경우만 바로 걸러낼 수 있습니다.
문자열로 합칠 필요도 없고, LIKE의 애매한 부분(Milkshake 같은 오탐)도 방지돼요. - SUM은 “이름이 Milk인 행이 몇 개나 있지?”를 세기 위함입니다
👉 핵심은 "존재 여부"만 확인하면 된다는 점입니다!
1. SUM(CASE WHEN NAME='Milk' THEN 1 ELSE 0 END)
→ Milk가 있으면 1, 여러 개여도 합치면 2, 3…
→ 어쨌든 0보다 크면 Milk가 있다는 의미
2. COUNT(CASE WHEN NAME='Milk' THEN 1 END)
→ Milk인 행만 카운트
→ 역시 0보다 크면 Milk 있음
🔹 LISTAGG란?
- 오라클에서 제공하는 집계 함수.
- 여러 행(Row)의 문자열 값을 하나로 합쳐서 하나의 문자열로 반환합니다.
- 보통 구분자(Separator)를 넣어서 표현합니다.
기본 문법
LISTAGG(컬럼명, '구분자') WITHIN GROUP (ORDER BY 정렬기준)
출력 결과
| DEPT_ID | EMP_LIST |
| 10 | Alice, Bob, Charlie |
| 20 | David, Eve |
즉, 같은 부서 직원 이름을 , 로 묶어서 한 행에 보여줍니다.
| 구분 | MySQL | Oracle |
| 문자열 합치기 (컬럼끼리 붙이기) |
CONCAT(first_name, ' ', last_name) | first_name || ' ' || last_name |
| 행(Row) 값 합치기 (여러 행 → 하나의 문자열) |
GROUP_CONCAT(emp_name ORDER BY emp_name SEPARATOR ', ') | LISTAGG(emp_name, ', ') WITHIN GROUP (ORDER BY emp_name) |
'코딩 테스트 > 02. SQL' 카테고리의 다른 글
| [프로그래머스]Oracle SQL_6(Lv4)/UNION ALL과 CONNECT BY (0) | 2025.10.03 |
|---|---|
| [프로그래머스]Oracle SQL_5(Lv4) (0) | 2025.10.02 |
| [프로그래머스]Oracle SQL_3(Lv4) (0) | 2025.09.29 |
| [프로그래머스]Oracle SQL_2(Lv4) (1) | 2025.09.28 |
| [프로그래머스]Oracle SQL_1(Lv4) (0) | 2025.09.25 |