안녕하세요.
오늘도 저번에 이어서 프로그래머스 SQL 고득점 Kit의 SELECT 문제들의 풀이를 정리해보겠습니다.
⚠️ 저의 정답이 항상 최고의 방법은 아닐 수 있습니다.
✨ 표시는 중요하다고 판단한 문제입니다.
재구매가 일어난 상품과 회원 리스트 구하기
SELECT A.USER_ID
,A.PRODUCT_ID
FROM ONLINE_SALE A
GROUP BY USER_ID, PRODUCT_ID
HAVING COUNT(*) > 1
ORDER BY A.USER_ID ASC, A.PRODUCT_ID DESC;
모든 레코드 조회하기
SELECT *
FROM ANIMAL_INS
ORDER BY ANIMAL_ID ASC;
역순 정렬하기
SELECT A.NAME
, A.DATETIME
FROM ANIMAL_INS A
ORDER BY ANIMAL_ID DESC;
✨오프라인/온라인 판매 데이터 통합하기
SELECT SUBSTR(SALES_DATE, 1, 10) AS SALES_DATE
, PRODUCT_ID
, USER_ID
, SALES_AMOUNT
FROM (
SELECT A.SALES_DATE
, A.PRODUCT_ID
, A.USER_ID
, A.SALES_AMOUNT
FROM ONLINE_SALE A
WHERE A.SALES_DATE LIKE '2022-03-%'
UNION
SELECT B.SALES_DATE
, B.PRODUCT_ID
, NULL USER_ID
, B.SALES_AMOUNT
FROM OFFLINE_SALE B
WHERE B.SALES_DATE LIKE '2022-03-%'
) AS C -- 파생테이블엔 ALIAS 필수
ORDER BY SALES_DATE, PRODUCT_ID, USER_ID;
파생 테이블(Derived Table)에는 꼭 alias(별칭)를 붙여야 합니다.
더보기
1️⃣ 파생 테이블 (Derived Table, 서브쿼리)
SELECT *
FROM (
SELECT USER_ID, SUM(SALES_AMOUNT) AS TOTAL
FROM ONLINE_SALE
GROUP BY USER_ID
) AS T
WHERE T.TOTAL > 10;
- FROM ( ... ) 형태로 서브쿼리를 만들고 alias 필수 (AS T)
- 쿼리 실행할 때마다 즉석에서 생성되는 임시 테이블
- 해당 SELECT 문 안에서만 사용 가능 (재사용 불가)
- 가독성이 떨어질 수 있음 (특히 쿼리가 길어지면 중첩 심해짐)
2️⃣ CTE (Common Table Expression, WITH문)
WITH C AS (
SELECT A.SALES_DATE
, A.PRODUCT_ID
, A.USER_ID
, A.SALES_AMOUNT
FROM ONLINE_SALE A
WHERE A.SALES_DATE LIKE '2022-03-%'
UNION
SELECT B.SALES_DATE
, B.PRODUCT_ID
, NULL AS USER_ID
, B.SALES_AMOUNT
FROM OFFLINE_SALE B
WHERE B.SALES_DATE LIKE '2022-03-%'
)
SELECT SUBSTR(SALES_DATE, 1, 10) AS SALES_DATE
, PRODUCT_ID
, USER_ID
, SALES_AMOUNT
FROM C
ORDER BY SALES_DATE, PRODUCT_ID, USER_ID;
- WITH ... AS (...) 구문으로 정의
- 마치 임시 뷰(View)처럼 재사용 가능 (같은 쿼리에서 여러 번 참조 가능)
- 가독성이 좋음 → 복잡한 쿼리 구조를 단계별로 나눠서 작성 가능
- 성능은 DBMS에 따라 다름 (일부 DBMS는 CTE를 매번 실행, 일부는 최적화해서 한 번만 실행)
한 줄 정리
👉 짧고 단순한 경우 → 파생 테이블
👉 길고 단계가 많은 경우 → CTE
더보기
FULL OUTER JOIN vs UNION vs UNION ALL
| 구분 | FULL OUTER JOIN | UNION | UNION ALL |
| 기준 | 조인 조건 (ON) | 단순 행 append | 단순 행 append |
| 결과 | 조건 맞으면 병합, 없으면 NULL 채움 | 중복 제거 후 합침 | 중복까지 포함해서 합침 |
| 중복 처리 | 조건 매칭 시 병합 | 자동 중복 제거 | 중복 유지 |
| 목적 | 관계형 데이터 매칭 | 집합 합집합 (Distinct) | 집합 합집합 (중복 포함) |
아픈 동물 찾기
SELECT ANIMAL_ID
, NAME
FROM ANIMAL_INS
WHERE INTAKE_CONDITION = "Sick";
어린 동물 찾기
SELECT ANIMAL_ID
, NAME
FROM ANIMAL_INS
WHERE INTAKE_CONDITION != "Aged"
ORDER BY ANIMAL_ID;
동물의 아이디와 이름
SELECT ANIMAL_ID
, NAME
FROM ANIMAL_INS
ORDER BY ANIMAL_ID;
여러 기준으로 정렬하기
SELECT ANIMAL_ID
, NAME
, DATETIME
FROM ANIMAL_INS
ORDER BY NAME ASC, DATETIME DESC;
상위 n개 레코드
# SELECT TOP 1 NAME
# FROM ANIMAL_INS
# ORDER BY DATETIME;
SELECT NAME
FROM ANIMAL_INS
ORDER BY DATETIME
LIMIT 1;
더보기
1️⃣ TOP 1
- 사용 DB: SQL Server (MSSQL), Sybase 등
- 문법:
SELECT TOP 1 컬럼1, 컬럼2 FROM 테이블명 ORDER BY 컬럼;
- 설명:
- TOP N → 결과 중 상위 N건만 가져오기
- 반드시 ORDER BY를 같이 쓰면 어떤 행이 "상위"인지 명확해짐
2️⃣ LIMIT
- 사용 DB: MySQL, PostgreSQL, SQLite 등
- 문법:
SELECT 컬럼1, 컬럼2 FROM 테이블명 ORDER BY 컬럼 LIMIT N;
- 설명:
- LIMIT N → 결과 중 상위 N건만 가져오기
- MySQL에서는 LIMIT N OFFSET M 형태로 건너뛸 행 수(M) + 가져올 행 수(N) 지정 가능
SELECT NAME, AGE
FROM STUDENTS
ORDER BY AGE DESC
LIMIT 3;
→ 나이 많은 학생 3명만 가져오기
🔹 비교 요약
| 항목 | TOP | LIMIT |
| DBMS | SQL Server | MySQL, PostgreSQL, SQLite |
| 문법 위치 | SELECT 뒤 | SELECT 뒤 아님 (마지막에) |
| 지원 기능 | 단순 상위 N건 | 상위 N건, OFFSET 가능 |
조건에 맞는 회원수 구하기
SELECT COUNT(*) AS USERS
FROM USER_INFO
WHERE AGE BETWEEN 20 AND 29
AND JOINED LIKE '2021%';