241023_TIL

J Lee·2024년 10월 23일
1

아무리 사소하더라도 배움이 없는 날은 없다.

SQL 문제풀이 복습


Leetcode

문제 링크
2트(9/4)에서는 이 문제를 풀 때 offset이라는 명령어를 썼다.
'offset을 쓰게 되면 출력된 결과에서 한 행을 건너뛰게 되므로
2번째로 높은 salary를 구할 수 있게 되'는 원리인데,

사실 이렇게 풀어도 똑같이 답이 나온다.
(중요한 건 해당하는 값이 없을 때는 null이 반환된다는 점)

SELECT Max(salary) AS "SecondHighestSalary"
FROM   Employee
WHERE  salary < (SELECT Max(salary)
                 FROM   Employee);

문제 자체가 어려운 건 아닌데
해당하는 값이 없을 때 null을 띄우도록 하는 게 어려운 점.
CTE를 써도 안 되고, window함수를 쓰면 가능은 한데 쿼리가 너무 복잡해진다.
offset을 쓰거나 (단, CTE로 쓰면 안되고 인라인뷰로)
아니면 오늘의 풀이처럼 서브쿼리를 활용하면 될 듯.

문제 링크
recursive cte를 만들 수 있으면 그 뒤로는 간단한 문제.

subtasks_count가 가장 큰 subtask_id이기도 하므로
1이 나올 때까지 값을 하나씩 줄여가면서
union한 결과를 full_task에 저장하고,
그 뒤로는 Executed와 join해서
아직 완료되지 않은 건을 찾아주기만 하면 됨.

WITH recursive full_task
AS
  (
         SELECT task_id,
                subtasks_count AS "all_task"
         FROM   Tasks
         UNION ALL
         SELECT task_id,
                all_task - 1
         FROM   full_task
         WHERE  all_task > 1)
  SELECT    f.task_id,
            f.all_task AS "subtask_id"
  FROM      full_task f
  LEFT JOIN Executed e
  ON        f.task_id = e.task_id
  AND       f.all_task = e.subtask_id
  WHERE     e.subtask_id IS NULL
  ORDER BY  1,
            2;

문제 링크
피벗테이블 만드는 문제.
그렇게 안 어렵다.

select
    product_id,
    max(case when store = 'store1' then price end) as "store1",
    max(case when store = 'store2' then price end) as "store2",
    max(case when store = 'store3' then price end) as "store3"
from Products
group by 1;

프로그래머스

문제 링크
서브쿼리와 join, concat을 조합한 문제.
모든 user_id가 다 필요한 건 아니므로
서브쿼리를 써서 3개 이상 게시글을 올린 유저부터 추린 후에
그 결과물과 join하고 주소와 전화번호를 불러왔다.

1트 때는 정답 쿼리는 따로 넣어놓지 않았구나..ㅎㅎ

SELECT u.user_id,
       nickname,
       Concat(city, ' ', street_address1, ' ', street_address2)         AS
       "전체주소",
       Concat(LEFT(tlno, 3), '-', Mid(tlno, 4, 4), '-', RIGHT(tlno, 4)) AS
       "전화번호"
FROM   used_goods_user u
       JOIN (SELECT writer_id
             FROM   used_goods_board
             GROUP  BY 1
             HAVING Count(*) >= 3) a
         ON u.user_id = a.writer_id
ORDER  BY 1 DESC;

문제 링크
서브쿼리로 결과를 먼저 만들어 놓고 join을 하든,
join을 한 뒤에 group by having을 쓰든 결과는 같다.
(1트(4/5) 때는 join 먼저 하고 group by로 결과를 나중에 뽑았다)

다만 이번에 풀 때는 join의 가짓수가 너무 많아질 것 같아서
서브쿼리로 결과를 한 번 줄여놓고 join하는 방법을 택함.

SELECT u.user_id,
       u.nickname,
       a.total AS "TOTAL_SALES"
FROM   USED_GOODS_USER u
       JOIN (SELECT writer_id,
                    Sum(price) AS "total"
             FROM   USED_GOODS_BOARD
             WHERE  status = 'DONE'
             GROUP  BY 1
             HAVING total >= 700000) a
         ON u.user_id = a.writer_id
ORDER  BY 3; 

문제 링크
where절로 조건을 줄 때 문자를 제어해서 조건을 짜는 문제.
네비게이션 앞이나 뒤에 다른 문자가 올 수 있으므로
앞뒤를 % 기호로 감싸줘야 한다.

SELECT CAR_ID,
       CAR_TYPE,
       DAILY_FEE,
       OPTIONS
FROM   CAR_RENTAL_COMPANY_CAR
WHERE  OPTIONS LIKE '%네비게이션%'
ORDER  BY 1 DESC;

문제 링크
group by와 having
그리고 대여기간을 구하기 위한 datediff만 알면 됨

SELECT CAR_ID,
       Round(Avg(Datediff(END_DATE, START_DATE) + 1), 1) AS "AVERAGE_DURATION"
FROM   CAR_RENTAL_COMPANY_RENTAL_HISTORY
GROUP  BY 1
HAVING AVERAGE_DURATION >= 7
ORDER  BY 2 DESC,
          1 DESC;

문제 링크
똑같이 medium으로 분류되더라도
leetcode 쪽이 훨씬 난이도가 높다.
이 문제는 level3이긴 하지만 정말 간단한 join 문제.

SELECT DISTINCT c.CAR_ID
FROM   CAR_RENTAL_COMPANY_CAR c
       JOIN CAR_RENTAL_COMPANY_RENTAL_HISTORY h
         ON c.CAR_ID = h.CAR_ID
WHERE  CAR_TYPE = '세단'
       AND Month(START_DATE) = '10'
ORDER  BY 1 DESC;
profile
기본기를 소홀히 하지 말자

0개의 댓글

관련 채용 정보