문제해결_sql - 코딩테스트연습

찬이·2022년 5월 17일
0

문제해결

목록 보기
3/3
post-thumbnail

출처 : 프로그래머스/Oracle

SQL과 관련된 문제풀이 중 하나의 문제를 발견하였다.

문제에서 원하는 바를 살펴보면,

  • 장바구니의 아이디를 조회하는 SQL문 작성
  • 단, 우유와 요거트를 동시에 구입한 장바구니이다.
  • 결과는 장바구니의 아이디 순으로 출력되어야 한다.

여기서 가장 중요한 부분은

<우유와 요거트를 동시에 구입한 장바구니>

이다.

우선, 해당 문제의 테이블 구조는 다음과 같다.

  • CART_PRODUCTS 테이블의 정보

    테이블 NAME정보
    ID테이블의 아이디
    CART_ID장바구니의 아이디
    NAME상품 종류
    PRICE가격

우선 주어진 정보만 가지고 코드를 작성해보자.

코드 작성

SELECT	*
FROM	CART_PRODUCTS
;

우선 나는 코드를 작성하기 앞서 전체 테이블을 조회하는 편이다.
참고로 수 많은 데이터를 가지고 있는 테이블일 경우에는 좋지 않은 방법이다.

하지만 이건 문제해결이므로 차근차근 풀어보도록 하자.

우선, 조회해야 할 정보는 장바구니의 ID, 즉 CART_ID이다.

SELECT	CART_ID
FROM	CART_PRODUCTS
;

이런 식으로 우선 CART_ID를 가져오도록 하자.

다음은 조건문인 WHERE의 차례이다.
앞서 살펴본 조건으로는 "우유"와 "요거트"가 모두 들어있는 CART_ID를 조회하는 것이다.

때문에 아래와 같이 sql문을 작성하였다.

SELECT	CART_ID
FROM	CART_PRODUCTS
WHERE	NAME IN('Milk', 'Yogurt')
;

이런 식으로 작성하면 결과값은 아래와 같다.

여기서 의아한 점을 알 수 있다.
더 확실하게 알기 위해서 SELECT 구문에 CART_ID와 더불어 NAME을 추가하였다.

이런 식으로 우유와 요거트를 모두 담은 장바구니가 출력된다.
하지만 여기서 한가지 짚고 넘어가야 할 문제가 있다.

문제에서 언급한 조건은 "동시에" 구입한 장바구니 ID를 조회하는 것이다.
즉, 결과값은 아래와 같이 출력되어야 마땅하다.

바로 위 사진과 비교해보면 CART_ID 286번은 Milk와 Yogurt를 모두 구매하였고,
때문에 결과값에 출력된 모습이다.

그럼 위 사진처럼 올바르게 결과값이 도출되기 위해서는 어떻게 코드를 작성해야 할까?

문제해결

SELECT	CART_ID
FROM	CART_PRODUCTS
WHERE	NAME IN('Milk', 'Yogurt')
;

위 코드와 같이 입력하였을 때는 CART_ID가 중복되어 출력된다는 것을 알 수 있다.
하나씩 코드를 입력해보자.

우선 'Milk'와 'Yogurt'를 구매한 CART_ID에 대한 정보를 도출하기 위해서
GROUP BY 코드를 사용할 필요가 있다.

SELECT	CART_ID
FROM	CART_PRODUCTS
WHERE	NAME IN('Milk', 'Yogurt')
GROUP BY CART_ID
;

이로써 우리는 CART_ID라는 테이블에 간섭할 수 있게 되었다.

원래 일반적인 구문에서 조건을 걸 때에는 WHERE를 사용하여 걸지만
GROUP BY에서는 "HAVING"을 사용하여 조건을 걸 수 있다.

그럼 어떤 조건을 걸어야 할까?

우리는 지금까지 본 결과값들을 가지고 하나의 사실을 알 수 있다.

  • 잘못 출력된 결과값은 CART_ID가 여러 개가 출력된다.
  • 올바르게 출력된 결과값은 CART_ID가 하나만 출력된다.

즉, CART_ID의 개수가 2개 미만이어야 올바르다는 것이다.

앞서 잘못 출력된 결과값을 다시 보자.

위 결과값을 자세히 보면

286번과 같이 요거트와 우유가 다 있는 경우도 있고,
287번같이 우유 하나만 있는 경우도 있고
맨 밑에 830번과 같이 요거트만 3개가 있는 경우도 있다.

그럼 이렇게 해보면 어떨까?

NAME(상품종류)의 중복을 제거한 수가 1보다 크면
"Milk"와 "Yogurt" 2개를 동시에 구매한 사람이 아닐까?

예를 들어보자.
위 사진에 맨 위에 286번이 구매한 상품의 경우
같은 상품의 중복을 제거한 "Yogurt"와 "Milk"의 2개이다.

287번 같은 경우는 어차피 하나만 구매하였으니 1개.

830번 같은 경우 똑같은 상품만 구매하였으니
같은 상품의 중복을 제거한 상품의 수는 1개이다.

즉, 우리는 <상품의 수>를 세는 것이 아닌 <상품의 종류의 수>를 세어야 하는 것이다.

그럼 아래와 같이 코드를 작성할 수 있다.

SELECT CART_ID
FROM CART_PRODUCTS
-- Milk와 Yogurt를 구매한 장바구니 조건
WHERE NAME IN ('Milk', 'Yogurt')
-- 장바구니를 기준으로
GROUP BY CART_ID
-- 한 장바구니가 구매한 상품이 1개보다 많을 경우 count 한다.
HAVING COUNT(DISTINCT NAME) > 1
-- 장바구니 ID를 기준으로 정렬한다.
ORDER BY CART_ID
;

문제가 원하는 것은 CART_ID만을 출력하는 것이므로,
이런식으로 코드를 작성하면 아래와 같이 정상적으로 출력이 된다.

  • 정리
  1. 해당 문제에서는 "우유"와 "요거트"를 동시에 구매한 CART_ID를 찾아야 한다.
  2. CART_ID가 구매한 상품의 총 개수가 아닌, 상품의 종류의 가지수를 찾아보자.
  3. 단, 똑같은 상품을 여러 개 구매하였을 경우 중복제거를 해주어야 한다.
profile
시작하는 코딩러입니다.

0개의 댓글