🌟🌟🌟 1. SELECT - [재구매가 일어난 상품과 회원 리스트 구하기] _ LEVEL 2
다음은 어느 의류 쇼핑몰의 온라인 상품 판매 정보를 담은 ONLINE_SALE 테이블 입니다.
동일한 날짜, 회원 ID, 상품 ID 조합에 대해서는 하나의 판매 데이터만 존재합니다.
ONLINE_SALE 테이블에서 동일한 회원이 동일한 상품을 재구매한 데이터를 구하여, 재구매한 회원 ID와 재구매한 상품 ID를 출력하는 SQL문을 작성해주세요.
결과는 회원 ID를 기준으로 오름차순 정렬해주시고 회원 ID가 같다면 상품 ID를 기준으로 내림차순 정렬해주세요.
[ 정답 쿼리 ]
SELECT user_id, product_id
FROM online_sale
GROUP BY user_id, product_id
HAVING COUNT(*) >= 2
ORDER BY 1, 2 DESC;
[ 풀이 ]
- 동일 고객, 동일 상품 재구매 = user_id, product_id를 key로 하는 중복 데이터 존재
- 하지만 MySQL에는 파이썬 pandas의 duplicated() 메서드처럼 중복 데이터를 관리하는 함수가 따로 존재하지 않음
- 이 경우, GROUP BY와 HAVING COUNT(*) ≥2 조건을 이용해 중복 데이터를 뽑아낼 수 있음!
- key로 잡을 필드들을 GROUP BY절에 명시
- HAVING COUNT(*) ≥2 : 해당 key들로 GROUP BY 했을 때 2개 이상으로 집계된다면 그게 곧 중복이라는 의미
🌟🌟🌟 2. SUM, MAX, MIN - [연도별 대장균 크기의 편차 구하기] _ LEVEL 2
대장균들은 일정 주기로 분화하며, 분화를 시작한 개체를 부모 개체, 분화가 되어 나온 개체를 자식 개체라고 합니다.
다음은 실험실에서 배양한 대장균들의 정보를 담은 ECOLI_DATA 테이블입니다.
분화된 연도(YEAR), 분화된 연도별 대장균 크기의 편차(YEAR_DEV), 대장균 개체의 ID(ID) 를 출력하는 SQL 문을 작성해주세요.
- 분화된 연도별 대장균 크기의 편차는 분화된 연도별 가장 큰 대장균의 크기 - 각 대장균의 크기
결과는 연도에 대해 오름차순으로 정렬하고 같은 연도에 대해서는 대장균 크기의 편차에 대해 오름차순으로 정렬해주세요.
[ 정답 쿼리 ]
# 풀이 1) 윈도우함수 활용
SELECT
YEAR(differentiation_date) AS `year`
, MAX(size_of_colony) OVER (PARTITION BY YEAR(differentiation_date)) - size_of_colony AS `year_dev`
, id
FROM ecoli_data
ORDER BY 1,2;
# 풀이 2) CTE 구문, LEFT JOIN 활용
WITH max_size AS
(
SELECT YEAR(differentiation_date) year
, MAX(size_of_colony) max_size_by_year
FROM ecoli_data
GROUP BY 1
)
SELECT
M.year
, (max_size_by_year - E.size_of_colony) year_dev
, id
FROM ecoli_data E
LEFT JOIN max_size M ON YEAR(E.differentiation_date) = M.year
ORDER BY 1, 2;
[ 풀이 ]
- 윈도우함수만 잘 사용하면, JOIN이나 서브쿼리 등을 불필요하게 사용해서 가독성을 떨어뜨리거나 구태여 복잡하게 코드를 짜지 않아도 된다
- 주의사항 : YEAR()는 MySQL 외의 다른 DBMS에서는 동작하지 않을 수 있으니 이런 경우엔 EXTRACT()를 사용하도록 하자
SELECT
EXTRACT(YEAR FROM differentiation_date) AS `year`
, MAX(size_of_colony) OVER (PARTITION BY EXTRACT(YEAR FROM differentiation_date)) - size_of_colony AS `year_dev`
, id
FROM ecoli_data
ORDER BY 1,2;
3. GROUP BY - [식품분류별 가장 비싼 식품의 정보 조회하기] _ LEVEL 4
다음은 식품의 정보를 담은 FOOD_PRODUCT 테이블입니다.
FOOD_PRODUCT 테이블에서 식품분류(CATEGORY)별로 가격이 제일 비싼 식품의 분류, 가격, 이름을 조회하는 SQL문을 작성해주세요.
이때 식품분류가 '과자', '국', '김치', '식용유'인 경우만 출력시켜 주시고 결과는 식품 가격을 기준으로 내림차순 정렬해주세요.
[ 정답 쿼리 ]
# 풀이 1) 윈도우 함수 활용
SELECT category, price, product_name
FROM
(
SELECT
*
, RANK() OVER (PARTITION BY category ORDER BY price DESC) AS ranking
FROM food_product
) SUB
WHERE ranking = 1 AND category IN ('과자', '국', '김치', '식용유')
ORDER BY price DESC;
# 풀이 2) WHERE절 조건 두 필드 결합
SELECT category, price, product_name
FROM food_product
WHERE (category, price) IN
(
SELECT category, MAX(price) price
FROM food_product
WHERE category IN ('과자', '국', '김치', '식용유')
GROUP BY category
)
ORDER BY price DESC;
# 풀이 3) 상관 서브쿼리 이용
SELECT category, price, product_name
FROM food_product P
WHERE price IN
(
SELECT MAX(price)
FROM food_product
WHERE category = P.category
)
AND category IN ('과자', '국', '김치', '식용유')
ORDER BY price DESC;
[ 풀이 ]
- 이전에 풀었던 ‘즐겨찾기가 가장 많은 식당 정보 출력하기’ 문제와 유사!
- 여러가지 방법으로 풀 수 있지만, 개인적으로 가장 직관적이라고 느껴졌던 WINDOW 함수를 이용해서 해결
- 서브쿼리 내에서 PARTITION BY 키워드를 이용해, 식품 분류별 가격 순위를 매기고, 외부쿼리에서 순위로 필터링을 걸어서 식품 분류별 가장 비싼 식품의 정보만 출력할 수 있음
4. SELECT - [모든 레코드 조회하기] _ LEVEL 1
ANIMAL_INS 테이블은 동물 보호소에 들어온 동물의 정보를 담은 테이블입니다.
동물 보호소에 들어온 모든 동물의 정보를 ANIMAL_ID순으로 조회하는 SQL문을 작성해주세요.
[ 정답 쿼리 ]
SELECT *
FROM animal_ins
ORDER BY animal_id;
5. JOIN - [상품 별 오프라인 매출 구하기] _ LEVEL 2
다음은 어느 의류 쇼핑몰에서 판매중인 상품들의 상품 정보를 담은 PRODUCT 테이블과 오프라인 상품 판매 정보를 담은 OFFLINE_SALE 테이블 입니다.
PRODUCT 테이블과 OFFLINE_SALE 테이블에서 상품코드 별 매출액(판매가 * 판매량) 합계를 출력하는 SQL문을 작성해주세요.
결과는 매출액을 기준으로 내림차순 정렬해주시고 매출액이 같다면 상품코드를 기준으로 오름차순 정렬해주세요.
[ 정답 쿼리 ]
SELECT product_code
, SUM(price * sales_amount) AS sales
FROM product P
JOIN offline_sale O ON P.product_id = O.product_id
GROUP BY product_code
ORDER BY 2 DESC, 1;
[ 풀이 ]
- 두 테이블에 각각 존재하는 상품 가격(price)정보와 판매량(sales_amount)의 연산을 통해 총 매출액을 계산하는 문제
- SUM(price * sales_amount) 는 의미상으로 MIN(price) * SUM(sales_amount) 로도 표현가능하다(테이블의 구조상 상품의 가격은 변하지 않으므로)
→ 하지만 가독성 측면에서는 첫 번째 표현이 더 적절하다고 생각
6. String, Date - [취소되지 않은 진료 예약 조회하기] _ LEVEL 4
다음은 환자 정보를 담은 PATIENT 테이블과 의사 정보를 담은 DOCTOR 테이블, 그리고 진료 예약목록을 담은 APPOINTMENT에 대한 테이블입니다.
PATIENT, DOCTOR 그리고 APPOINTMENT 테이블에서 2022년 4월 13일 취소되지 않은 흉부외과(CS) 진료 예약 내역을 조회하는 SQL문을 작성해주세요.
진료예약번호, 환자이름, 환자번호, 진료과코드, 의사이름, 진료예약일시 항목이 출력되도록 작성해주세요. 결과는 진료예약일시를 기준으로 오름차순 정렬해주세요.
[ 정답 쿼리 ]
SELECT A.apnt_no, pt_name, A.pt_no, A.mcdp_cd, dr_name, apnt_ymd
FROM appointment A
JOIN patient P ON A.pt_no = P.pt_no
JOIN doctor D ON A.mddr_id = D.dr_id
WHERE apnt_ymd LIKE '2022-04-13%'
AND apnt_cncl_yn = "N"
AND A.mcdp_cd = "CS"
ORDER BY apnt_ymd;
[ 풀이 ]
- 출력해야 하는 정보 중 환자 이름(pt_name)은 PATIENT 테이블에, 의사 이름(dr_name)은 DOCTOR 테이블에 존재하고 있으므로 해당 문제는 모든 테이블을 조인해야 함
- 날짜에 대한 조건은 DATE_FORMAT() 함수를 쓰는 것이 가장 정석적인 방법이지만, 먼저 SELECT * FROM TABLE LIMIT 3 의 구문으로 DATE 형식을 확인하고, LIKE 키워드와 와일드카드를 이용해서 표현하는 것도 가능!
'SQL' 카테고리의 다른 글
[프로그래머스] 8주차 MySQL 스터디 1 (2) | 2024.06.04 |
---|---|
[프로그래머스] 7주차 MySQL 스터디 2 (1) | 2024.06.04 |
[프로그래머스] 6주차 MySQL 스터디 (1) | 2024.06.03 |
[프로그래머스] 5주차 MySQL 스터디 (0) | 2024.04.29 |
[프로그래머스] 4주차 MySQL 스터디 2 (0) | 2024.04.16 |