SQL

GROUP_CONCAT 응용

zzugest1 2023. 1. 2. 20:47

https://school.programmers.co.kr/learn/courses/30/lessons/62284#qna

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

 

 

데이터 분석 팀에서는 우유(Milk)와 요거트(Yogurt)를 동시에 구입한 장바구니가 있는지 알아보려 합니다. 우유와 요거트를 동시에 구입한 장바구니의 아이디를 조회하는 SQL 문을 작성해주세요. 이때 결과는 장바구니의 아이디 순으로 나와야 합니다.

 

예시

 

예를 들어 CART_PRODUCTS 테이블이 다음과 같다면

ID CART_ID NAME PRICE
1630 83 Cereal 3980
1631 83 Multipurpose Supply 3900
5491 286 Yogurt 2980
5504 286 Milk 1880
8435 448 Milk 1880
8437 448 Yogurt 2980
8438 448 Tea 11000
20236 1034 Yogurt 2980
20237 1034 Butter 4890
  • 83번 장바구니에는 Milk와 Yogurt가 모두 없습니다.
  • 286번 장바구니에는 Milk와 Yogurt가 모두 있습니다.
  • 448번 장바구니에는 Milk와 Yogurt가 모두 있습니다.
  • 1034번 장바구니에는 Milk는 없고 Yogurt만 있습니다.

따라서 SQL 문을 실행하면 다음과 같이 나와야 합니다.

CART_ID
286
448

 

정답 

SELECT DISTINCT(A.CART_ID) FROM CART_PRODUCTS AS A
RIGHT JOIN (SELECT CART_ID, GROUP_CONCAT(DISTINCT NAME) AS NAME FROM CART_PRODUCTS 
WHERE NAME LIKE ('%Milk%') OR NAME LIKE ('%Yogurt%')
GROUP BY CART_ID 
HAVING NAME LIKE ('%,%')) AS B
ON A.CART_ID=B.CART_ID
ORDER BY CART_ID

GROUP_CONCAT은 그룹별로 컬럼 데이터(문자열)를 묶을때 사용하는 함수이다.

 

예시를 들면 

animal name
monkey Lo
monkey Jay
monkey Jayce
elephant pink
elephant Tayo
elephant K

위와 같이 그룹(컬럼)에 따라 데이터가 있는 상황에서,

아래와 같이 그룹별로 문자열을 묶어서 출력할 때 쓰이는 함수이다.

animal name
elephant K,pink,Tayo
monkey Jay,Jayce,Lo

 

 

 

위 정답코드 B테이블의 HAVING절 이전까지의 코드는 다음과 같다.

CART_ID NAME
286 Milk,Yogurt
287 Milk
448 Milk,Yogurt
578 Milk,Yogurt
636 Milk
789 Yogurt
830 Yogurt
977 Milk,Yogurt
996 Milk
1034 Yogurt
1048 Milk,Yogurt

 

위 문제는 우유와 요거트를 동시에 구매한 카드를 찾는 문제이다. 필자는 이 조건을 만족하는 행만을 추출하는 법을 

HAVING NAME LIKE ('%,%')을 이용해 해결했다. 그 결과는 다음과 같다. 

CART_ID NAME
286 Milk,Yogurt
448 Milk,Yogurt
578 Milk,Yogurt
977 Milk,Yogurt
1048 Milk,Yogurt

 

문제의 조건을 만족하는 카드 아이디를 찾았고 RIGHT JOIN을 이용해 최종적으로 해결했다.

하지만 필자가 작성한 코드는 매우 복잡한 코드이다. 

 

모범답안

SELECT CART_ID
FROM CART_PRODUCTS
WHERE NAME IN ('Milk', 'Yogurt')
GROUP BY CART_ID
HAVING COUNT(DISTINCT(NAME)) >= 2
ORDER BY CART_ID

다음과 같은 간단한 코드로 풀 수 있는 문제이다. 

 

HAVING절 이전까지의 코드를 NAME열을 추가해 실행한 결과는 다음과 같다.

CART_ID NAME
286 Yogurt
287 Milk
448 Milk
578 Milk
636 Milk
789 Yogurt
830 Yogurt
977 Milk
996 Milk
1034 Yogurt
1048 Yogurt

필자가 위에서 구한 결과와 동일한 카드 아이디이다. 이를 HAVING COUNT(DISTINCT(NAME)) >= 2를 이용해 쉽게 구하였다. 

 

이 문제는 GROUP_CONCAT같은 어려운 함수를 이용하지 않고도 기본에 충실해 풀 수 있는 문제였다.