LeetCode SQL 585: Investments in 2016 - 코드 리뷰 및 분석
제출하신 MySQL 쿼리 코드는 문제의 요구사항을 정확히 충족하며 정상적으로 작동합니다. 로직은 명확하며, JOIN
과 GROUP BY
를 효과적으로 사용하여 두 가지 조건을 만족하는 정책 보유자를 필터링하고 있습니다.
# Write your MySQL query statement below
select round(sum(tiv_2016), 2) as tiv_2016
from insurance
join (
select tiv_2015
from insurance
group by tiv_2015 having count(tiv_2015) > 1
) t1 using(tiv_2015)
join (
select lat, lon
from insurance
group by lat, lon having count(lon) = 1
) t2 using(lat, lon)
코드 분석:
FROM insurance
: 기본 테이블을insurance
로 지정합니다.JOIN (...) t1 using(tiv_2015)
: 첫 번째JOIN
은tiv_2015
값을 기준으로 합니다.t1
서브쿼리:select tiv_2015 from insurance group by tiv_2015 having count(tiv_2015) > 1
- 목적:
insurance
테이블에서tiv_2015
값이 2번 이상 나타나는 (즉, 다른 사람과 동일한tiv_2015
값을 가지는)tiv_2015
값들을 찾습니다. - 결과: 이
JOIN
을 통해insurance
테이블에서tiv_2015
값이 다른 사람과 공유되는 행들만 남게 됩니다. (문제의 첫 번째 조건 충족)
JOIN (...) t2 using(lat, lon)
: 두 번째JOIN
은lat
와lon
값을 기준으로 합니다.t2
서브쿼리:select lat, lon from insurance group by lat, lon having count(lon) = 1
(여기서count(lon)
대신count(*)
또는count(lat)
를 사용해도 동일하며, 가독성 측면에서count(*)
가 더 일반적일 수 있습니다.)- 목적:
insurance
테이블에서 (lat
,lon
) 조합이 유니크한 (즉, 다른 사람과 같은 위치에 있지 않은) 위치 정보들을 찾습니다. - 결과: 이
JOIN
을 통해 이전 단계에서 필터링된 결과 중 위치 (lat
,lon
)가 유니크한 행들만 남게 됩니다. (문제의 두 번째 조건 충족)
select round(sum(tiv_2016), 2) as tiv_2016
: 최종적으로 필터링된 행들의tiv_2016
값을 합산하고, 그 결과를 소수점 둘째 자리까지 반올림하여tiv_2016
이라는 별칭으로 출력합니다.
결론: 코드는 논리적으로 정확하며 문제의 요구사항을 잘 반영하고 있습니다.
다른 방식의 솔루션
문제 해결에는 여러 가지 접근 방식이 가능합니다. 다음은 몇 가지 대안적인 SQL 솔루션입니다.
1. 윈도우 함수 (Window Functions) 사용:
윈도우 함수 COUNT() OVER()
를 사용하면 서브쿼리와 조인 없이 한 번의 스캔으로 각 행에 대해 조건을 확인할 수 있어 더 효율적일 수 있습니다.
SELECT
ROUND(SUM(tiv_2016), 2) AS tiv_2016
FROM (
SELECT
tiv_2016,
-- 각 tiv_2015 값의 전체 개수를 계산
COUNT(*) OVER (PARTITION BY tiv_2015) as tiv_count,
-- 각 (lat, lon) 조합의 전체 개수를 계산
COUNT(*) OVER (PARTITION BY lat, lon) as loc_count
FROM
Insurance
) AS SubQuery
WHERE
-- tiv_2015 값이 1개 초과 (다른 사람과 공유)하고
tiv_count > 1
-- (lat, lon) 조합이 1개 (유니크한 위치)인 경우
AND loc_count = 1;
- 장점: 코드가 간결하고, 데이터베이스가 테이블을 여러 번 스캔할 필요가 줄어들어 성능상 이점이 있을 수 있습니다.
- 단점: 윈도우 함수를 지원하는 SQL 버전에서만 사용 가능합니다. (대부분의 최신 RDBMS는 지원)
2. WHERE
절과 IN
/ NOT IN
사용:
서브쿼리를 JOIN
대신 WHERE
절의 IN
조건과 결합하여 사용할 수 있습니다.
SELECT
ROUND(SUM(tiv_2016), 2) AS tiv_2016
FROM
Insurance
WHERE
-- 조건 1: tiv_2015 값이 다른 사람들과 공유되는 값 목록에 포함되어야 함
tiv_2015 IN (
SELECT tiv_2015
FROM Insurance
GROUP BY tiv_2015
HAVING COUNT(*) > 1
)
AND
-- 조건 2: (lat, lon) 조합이 유니크한 위치 목록에 포함되어야 함
-- (MySQL, PostgreSQL 등 튜플 비교 지원)
(lat, lon) IN (
SELECT lat, lon
FROM Insurance
GROUP BY lat, lon
HAVING COUNT(*) = 1
);
- 장점: 각 조건을 명확하게
WHERE
절로 표현할 수 있습니다. - 단점: 서브쿼리의 결과 집합이 클 경우
IN
연산자의 성능이JOIN
이나EXISTS
보다 떨어질 수 있습니다.(lat, lon)
튜플 비교는 모든 RDBMS에서 지원되지 않을 수 있습니다.
3. WHERE
절과 EXISTS
/ NOT EXISTS
사용:
EXISTS
및 NOT EXISTS
를 사용하여 각 행에 대해 조건 충족 여부를 확인할 수 있습니다. 이는 상관 서브쿼리(Correlated Subquery)를 활용하는 방식입니다.
SELECT
ROUND(SUM(i1.tiv_2016), 2) AS tiv_2016
FROM
Insurance i1
WHERE
-- 조건 1: i1과 다른 pid를 가지면서 tiv_2015 값이 같은 행이 존재하는가?
EXISTS (
SELECT 1
FROM Insurance i2
WHERE i2.tiv_2015 = i1.tiv_2015 AND i2.pid <> i1.pid
)
AND
-- 조건 2: i1과 다른 pid를 가지면서 lat, lon 값이 같은 행이 존재하지 않는가?
NOT EXISTS (
SELECT 1
FROM Insurance i3
WHERE i3.lat = i1.lat AND i3.lon = i1.lon AND i3.pid <> i1.pid
);
- 장점:
IN
보다 성능상 이점이 있는 경우가 많으며, SQL 표준에 잘 부합합니다. 조건의 의미를 직접적으로 표현합니다. - 단점: 코드가 조금 더 길어질 수 있습니다.
요약:
제출하신 코드는 좋은 솔루션입니다. 다른 대안들 (특히 윈도우 함수나 EXISTS
)은 특정 상황에서 가독성이나 성능 면에서 장점을 가질 수 있으므로, 다양한 SQL 작성 방식을 알아두는 것이 좋습니다. LeetCode와 같은 환경에서는 여러 솔루션이 모두 정답으로 처리될 가능성이 높습니다.
'Algorithm' 카테고리의 다른 글
[17144] 미세먼지 안녕! 문제 분석 및 리뷰 (0) | 2025.03.30 |
---|---|
[16236] 아기 상어 문제 분석 및 리뷰 (0) | 2025.03.30 |
[LeetCode SQL] 1321: Restaurant Growth 코드 리뷰 및 분석 (0) | 2025.03.27 |
[LeetCode SQL] 1341: Movie Rating 코드 리뷰 및 분석 (0) | 2025.03.27 |
[16234] 인구 이동 문제 리뷰 및 코드 개선 (0) | 2025.03.22 |