취업준비/코딩테스트 문제 풀이

[프로그래머스 SQL 코딩테스트 연습] 헤비 유저가 소유한 장소

상급닌자연습생 2024. 5. 27. 13:53

🤔 문제

`PLACES` 테이블은 공간 임대 서비스에 등록된 공간의 정보를 담은 테이블입니다.

`PLACES` 테이블의 구조는 다음과 같으며 `ID`, `NAME`, `HOST_ID`는 각각 공간의 아이디, 이름, 공간을 소유한 유저의 아이디를 나타냅니다. `ID`는 기본키입니다.

 

이 서비스에서는 공간을 둘 이상 등록한 사람을 "헤비 유저"라고 부릅니다. 헤비 유저가 등록한 공간의 정보를 아이디 순으로 조회하는 SQL문을 작성해주세요.

 

 

예시

예를 들어, `PLACES` 테이블이 다음과 같다면

 

  • 760849번 유저는 공간을 3개 등록했으므로 이 유저는 헤비유저입니다.
  • 30900122번 유저는 공간을 2개 등록했으므로 이 유저는 헤비유저입니다.
  • 21058208번 유저는 공간을 1개 등록했으므로 이 유저는 헤비유저가 아닙니다.

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

 

 

 

 

 

 

 


💻 나의 풀이

SELECT *
FROM PLACES
WHERE HOST_ID IN (
    SELECT HOST_ID
    FROM PLACES
    GROUP BY HOST_ID
    HAVING COUNT(ID) > 1
)
ORDER BY ID;

 

  1. 헤비 유저만 모아둔 서브 쿼리를 생성
  2. 서브 쿼리에 해당하는 유저ID를 조회
  3. 유저 ID를 바탕으로 `PLACES`테이블에서 일치하는 행들을 공간ID 기준 오름차순 정렬하여 조회

 

 

실행결과

 

 

 

 

 

 

결과

 

 

 

 

 

 

 


🖍 오답노트

틀린 이유

처음에 이런식으로 풀이를 작성했다.

SELECT *
FROM PLACES
GROUP BY HOST_ID
HAVING COUNT(ID) > 1
ORDER BY ID;

 

실행 결과는 다음과 같이 나온다.

 

`GROUP BY` 사용 시 반환되는 행

  • `GROUP BY HOST_ID`는 각 `HOST_ID` 별로 그룹화된 결과를 반환한다. 하지만 이 결과는 각 `HOST_ID`별 하나의 행만 반환하게 된다.

 

`SELECT`와 `GROUP BY`절

  • `SELECT` 절에 포함된 모든 컬럼은 집계함수(`COUNT`. `SUM` 등)와 함께 사용되거나 `GROUP BY`절에 포함되어야 한다.
  • 위의 쿼리에서는 `SELECT *`로 모든 컬럼을 선택하고 있는데, `GROUP BY HOST_ID`와 호환되지 않기 때문에 SQL 문법 오류가 발생하게 된다.

 

 

 

 

다른 풀이

1) 서브 쿼리를 생성해서 JOIN하는 방법

SELECT P.ID, P.NAME , P.HOST_ID
FROM PLACES P 
JOIN (SELECT * 
		FROM PLACES 
        GROUP BY HOST_ID 
        HAVING COUNT(*) >= 2) A ON (P.HOST_ID = A.HOST_ID)
ORDER BY P.ID;

 

 

 

 

 

2) EXISTS를 사용하는 방법

SELECT *
FROM PLACES P1
-- 아래 조건에 해당하는 행 조회
WHERE EXISTS( -- 서브 쿼리의 결과가 존재할 경우 TRUE 반환
	SELECT 1
    FROM PLACES P2
    WHERE P1.HOST_ID = P2.HOST_ID
    GROUP BY HOST_ID
    HAVING COUNT(ID) > 1
)
ORDER BY ID;

 

  • `SELECT 1` : 해당 절에 컬럼이 불필요하기 때문에 의미 없는 1을 기입해서 사용
    • 1 = `TRUE`
    • 존재 유무만 간단하게 판별하는데 사용됨

 

 

 

 

 

3) Window 함수를 사용하는 방법

WITH COUNT_RESULT AS(
	SELECT ID, 
    		NAME, 
            HOST_ID,
            COUNT(1) OVER(PARTITION BY HOST_ID) as cnts
    FROM PLACES
)
SELECT ID, NAME, HOST_ID
FROM COUNT_RESULT
WHERE cnts > 1
ORDER BY 1;

 

데이터 웨어하우스에서는 위의 쿼리가 보다 효율적일 것이다.

시간적 효율성 측면에서 `GROUP BY`, `JOIN` < `Window`함수, `Map`

 

 

 

 

 


✅ 핵심 정리

1. IN

: 해당되는 조건 내에 있는 모든 값들을 확인한다.

  • `()`안에 특정 값, 서브쿼리가 올 수 있음
  • 서브 쿼리 결과를 모두 수행 (데이터의 모든 값을 확인)

 

 

2. EXISTS

: 해당되는 조건 내에 값이 있는지 없는지를 판단한다. 

  • `()` 안에 서브쿼리만 올 수 있음
  • 값이 1개라도 있다면 `TRUE`를 반환하고 더 이상 수행하지 않는다.
  • 해당하는 값이 없다면 `FALSE`를 반환한다.

 

 

 

 

 

 


🔗 References

[EXISTS를 활용한 풀이 참고]

https://velog.io/@rgunny/SQLProgrammers-%ED%97%A4%EB%B9%84-%EC%9C%A0%EC%A0%80%EA%B0%80-%EC%86%8C%EC%9C%A0%ED%95%9C-%EC%9E%A5%EC%86%8C

 

[SQL/Programmers] 헤비 유저가 소유한 장소

프로그래머스 - 헤비 유저가 소유한 장소, 2021 Dev-Matching 웹 백앤드, SQL 풀이

velog.io

 

 

 

 

 

좀 더 공부해볼 것들

- Map & Shuffling에 대해 알아보기
- Join Strategy에 대해 알아보기 (Broadcast join, Merge sort join ...)