SQL
QCC | 7회차 코드 리뷰 & 피드백 (+마지막 qcc)
성장하는 쿠키의 로그 기록
2025. 3. 21. 14:45
☑️ 좋아요를 받지않은 페이지 조회
[문제]
[문제 풀이]
내 코드
SELECT DISTINCT p.page_id AS page_id
FROM pages p
LEFT JOIN page_likes pl ON p.page_id =pl.page_id
WHERE pl.page_id IS NULL
ORDER BY 1;
이슈 및 해결 과정
- left join 후 null 값 집계 하는 문제
- page_id 만 출력하는 부분에서, group by 쓸지 distinct 쓸지 고민하다가 한줄 추가하기 싫어서 distinct로 해결
- 실무에서 사용한다면 group by 가 더 적합할듯
한줄 포인트
- pass
☑️ 티커별 최고가/최저가와 해당날짜 조회하기
[문제]
[문제 풀이]
내 코드
-- 1. high /low 의 open 과 일짜 각각cte로 만들어서 join 해주기 -> high/low값 각각집계해서 최적화 필요
WITH high_t AS(
SELECT date,ticker,open
,DENSE_RANK () OVER (PARTITION BY ticker ORDER BY open DESC) AS high
FROM stock_prices
WHERE OPEN IS NOT NULL
), low_t AS(
SELECT date,ticker,open
,DENSE_RANK () OVER (PARTITION BY ticker ORDER BY open asc) AS low
FROM stock_prices
WHERE OPEN IS NOT NULL
), high_t2 AS(
SELECT ticker
,DATE_FORMAT(date,'%Y%m') AS highest_mth
,OPEN AS highest_open
FROM high_t
WHERE high=1
), low_t2 AS(
SELECT ticker
,DATE_FORMAT(date,'%Y%m') AS lowest_mth
,OPEN AS lowest_open
FROM low_t
WHERE low=1
)
SELECT h.ticker,highest_mth,highest_open,lowest_mth,lowest_open
FROM high_t2 h
INNER JOIN low_t2 l ON h.ticker =l.ticker
ORDER BY ticker;
내코드2 (high /low 각 테이블에서 구한 후 집계하기)
-- WHERE 절 다중컬럼 서브쿼리 활용해서 HIGH/LOW CTE 각각 만들어서 해결
WITH high AS (
SELECT ticker,DATE_FORMAT(date,'%Y%m') AS highest_mnth,OPEN AS highest_open
FROM stock_prices
WHERE (ticker,open) IN (SELECT ticker,MAX(OPEN) FROM stock_prices GROUP BY ticker)
AND OPEN IS NOT null
),low AS (
SELECT ticker,DATE_FORMAT(date,'%Y%m') AS lowest_mnth,OPEN AS lowest_open
FROM stock_prices
WHERE (ticker,open) IN (SELECT ticker,MIN(OPEN) FROM stock_prices GROUP BY ticker)
AND OPEN IS NOT null
)
SELECT h.ticker,highest_mnth,highest_open,lowest_mnth,lowest_open
FROM high h
INNER JOIN low l ON h.ticker=l.ticker
ORDER BY 1
최종 최적화 쿼리
-- 순서 부여 CTE 만든후, CASE WHEN 조건으로 피벗팅
WITH rank_t AS(
SELECT DATE_FORMAT(date,'%Y%m') AS dt,ticker,open
,DENSE_RANK () OVER (PARTITION BY ticker ORDER BY open DESC) AS high
,DENSE_RANK () OVER (PARTITION BY ticker ORDER BY open ASC) AS low
FROM stock_prices
WHERE OPEN IS NOT NULL
)
SELECT ticker
,MAX(CASE WHEN high =1 THEN dt END) AS highest_mnth
,MAX(CASE WHEN high =1 THEN open END) AS highest_open
,MAX(CASE WHEN low =1 THEN dt END) AS lowest_mnth
,MAX(CASE WHEN low =1 THEN open END) AS lowest_open
FROM rank_t
GROUP BY ticker
ORDER BY ticker
이슈 및 해결 과정
- 문제 ) 최고가 /최저가 값만 추출하는게 아니라, 그 값의 날짜까지 같이 추출해주어야함
- 코드1 ) 최고가/최고가일자/최저가/최저가일자 각각 4개의 cte 만들어서 최종 아우터쿼리에서 join
- 코드2 ) 최고가&최고가일자 / 최저가&최저가일자 각각 cte로 생성 ( 값 - 일자를 가져오기 위해 다중컬럼 서브쿼리 활용)
- 쿼리는 짧아졌으나, 다중컬럼 서브쿼리는 리소스가 많이 듦
- 코드3 - 최적화) 최고가/최저가를 각각 넘버링 해준후 아우터쿼리에서 피벗팅 & 그룹화 뽑아줌
한줄 포인트
- pass
- 값 - 해당 날짜를 여러개 조회해야하는경우 넘버링 & 피벗팅+ 그룹바이 활용!!!!!!!
☑️ 모든 서버의 총 실행시간 집계하기
[문제]
[문제 풀이]
내 코드 -> 오답
WITH organized AS( -- 혹시 몰라 정렬 & 단독이벤트 제외
SELECT *
FROM server_utilization s1
WHERE server_id IN (SELECT server_id FROM server_utilization GROUP BY server_id HAVING COUNT(DISTINCT session_status) =2)
ORDER BY server_id,status_time
), time_t AS (
SELECT server_id,session_status
,status_time AS start_time
,LEAD(status_time) OVER(PARTITION BY server_id) AS stop_time
FROM organized
), time_diff AS(
SELECT *
,FLOOR(TIMESTAMPDIFF(SECOND,START_time,stop_time)/86400) AS diff
FROM time_t
WHERE session_status= 'start'
)
SELECT SUM(diff) AS total_uptime_days
FROM time_diff;
수정 코드
WITH organized AS( -- 혹시 몰라 정렬 & 단독이벤트 제외
SELECT *
FROM server_utilization s1
WHERE server_id IN (SELECT server_id FROM server_utilization GROUP BY server_id HAVING COUNT(DISTINCT session_status) =2)
ORDER BY server_id,status_time
), time_t AS (
SELECT server_id,session_status
,status_time AS start_time
,LEAD(status_time) OVER(PARTITION BY server_id) AS stop_time
FROM organized
), time_diff AS(
SELECT *
,TIMESTAMPDIFF(SECOND,START_time,stop_time)/86400 AS diff
FROM time_t
WHERE session_status= 'start'
)
SELECT FLOOR(SUM(diff)) AS total_uptime_days
FROM time_diff;
정답 코드
WITH running_time AS (
SELECT *
, LEAD(status_time) OVER (PARTITION BY server_id ORDER BY status_time) next_status_time
, LEAD(session_status) OVER (PARTITION BY server_id ORDER BY status_time) next_session_status
FROM server_utilization
), server_uptime_second AS (
SELECT server_id
, FLOOR(SUM(TIMESTAMPDIFF(SECOND, status_time, next_status_time) / 86400)) uptime_days
FROM running_time
WHERE session_status = 'start'
AND next_session_status = 'stop'
GROUP BY 1
)
SELECT SUM(uptime_days) AS total_uptime_days
FROM server_uptime_second;
이슈 및 해결 과정
- 오답 이유 : 내림 순서 오류
- 일자로 변경 후 -> 합집계 -> 소수점 내림 해야함
한줄 포인트
- FAIL
- 행단위로 시작- 끝 시각 저장되어있는 경우,
- 끝시각 LEAD로 가져온후 -> 원본 시작시각 & LEAD 끝시각 필터링 -> TIMESTAMPDIFF -> 합 집계
전체 QCC 회고 (1-7회차)
더보기
마지막 QCC 까지 끝났다.
QCC 진행하면서 느낀점은 문제의 디테일/ 쿼리의 디테일을 자꾸 놓친다는 것
3번 문제에서 소수점 내림차를 먼저 해버린다거나, 6회차에서 숫자1을 문자 1로 타입을 잘못 출력한다거나..
결론은, 실무에서도 디테일을 놓치면 전체 값이 크게 틀어지는 경우가 있으니 조건을 잘 파악하고 놓치지 않는 연습이 더 필요하겠다.