241029_TIL

J Lee·2024년 10월 29일
0

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

SQL 문제풀이 복습


Leetcode

문제 링크
date를 형식에 맞게 변환하는 문제.

  • %W : 요일 이름을 풀버전으로 반환한다. (e.g. Tuesday)
    만약 소문자로 %w를 쓰게 되면 요일을 숫자 형태로 반환한다. 월요일이 1부터 시작되므로 화요일은 2로 나오는 식.

  • %M %e : M도 마찬가지로 월 이름을 풀버전으로 반환한다. (e.g. April)
    이것도 소문자로 %m으로 쓰면 그냥 숫자 형태로 04처럼 나온다. date_format 나올 때 맨날 쓰던 %Y-%m-%d에서 보던 그것.

    뒤의 %e는 날짜를 숫자 형태로 반환하는데, %d와의 차이점은 한자릿수 앞에 0이 안 붙는다는 점. 예를 들어 날짜가 9일이라고 하면 %d는 09로 반환하는데, %e는 그냥 9로 나온다. 이 문제에서는 그냥 9로 출력되어야 하므로 %e를 쓰면 됨. 참고로 %E처럼 대문자로 쓰면 뭐 없고 그냥 영문자 E가 나온다.

  • %Y : 년도를 4자리의 풀버전으로 반환한다. (e.g. 2024)
    만약 %y처럼 소문자로 쓰게 되면 앞의 두 자리는 날아가고 24, 23, 22 이런 식으로 년도의 뒷 2자리만 나오게 된다.

SELECT DATE_FORMAT(day, "%W, %M %e, %Y") AS "day"
FROM   Days;

문제 링크
말을 이해하는 게 어려운..ㅋㅋ 문제
서브쿼리를 쓰면 너무 복잡해질 것 같아서 오늘은 CTE로.

WITH result
     AS (SELECT order_id,
                Max(quantity) AS "max",
                Avg(quantity) AS "avg"
         FROM   OrdersDetails
         GROUP  BY 1)
SELECT order_id
FROM   result
WHERE  max > (SELECT Max(avg)
              FROM   result);

문제 링크
case when을 쓸 때 조건을 2개 주는 문제.

odd_number인지 판별하려면 2로 나눴을 때 나머지가 1인지를 보면 되고,
(파이썬 문법과 동일)
이름이 M으로 시작하는 경우에 해당하면 안 되므로 not like 'M%'로 써 주면 된다.
특히 문자열 제어하는 이 부분이 자주 안 써버릇하면 헷갈리기 쉬움.

SELECT employee_id,
       CASE
         WHEN employee_id%2 = 1
              AND name NOT LIKE 'M%' THEN salary
         ELSE 0
       end AS "bonus"
FROM   Employees
ORDER  BY 1;

프로그래머스

문제 링크

SELECT YEAR(SALES_DATE)          AS "YEAR",
       MONTH(SALES_DATE)         AS "MONTH",
       GENDER,
       COUNT(DISTINCT o.USER_ID) AS "USERS"
FROM   ONLINE_SALE o
       JOIN USER_INFO u
         ON o.USER_ID = u.USER_ID
WHERE  GENDER IS NOT NULL
GROUP  BY 1,
          2,
          3
ORDER  BY 1,
          2,
          3;

문제 링크
예시를 이상하게 주네;

SELECT CONCAT(LEFT(PRICE, 1), '0000') AS "PRICE_GROUP",
       COUNT(PRODUCT_ID)              AS "PRODUCTS"
FROM   PRODUCT
GROUP  BY 1
ORDER  BY 1;

문제 링크

SELECT LEFT(PRODUCT_CODE, 2) AS "CATEGORY",
       COUNT(*)              AS "PRODUCTS"
FROM   PRODUCT
GROUP  BY 1
ORDER  BY 1;

문제 링크

SELECT COUNT(*) AS "USERS"
FROM   USER_INFO
WHERE  age IS NULL;

문제 링크
아직도 복수정답이 인정되는 듯한 애매한 문제.
리트코드와 비교했을 때의 프로그래머스의 두드러진 약점이 이거라고 생각한다.
(물론 리트코드의 출제도 완벽한 건 아니지만!)

1트(4/7) 때의 포스팅을 보니 서브쿼리를 쓰는 게 익숙하지 않아서
공동 1등이 여러 명일 때의 쿼리를 소화하지 못했더라.
그래서 그냥 김민재의 결과만 출력하고 정답으로 인정받았던 것 같은데,
어렵게 생각할 것 없이 그냥 서브쿼리를 두 번 쓰면 된다.
지금은 자연스럽게 생각이 드는 것도 그 당시엔 그렇게 어려웠었나 보다.

제일 안쪽 서브쿼리부터 해석하면

  1. 멤버 ID별로 그루핑했을 때 가장 많이 리뷰를 단 건수가 몇 건인지 세고
  2. 그 건수에 해당하는 리뷰를 단 멤버 ID를 조회한 다음
  3. 멤버 ID가 2에 해당하는 애들만 데리고 오면 된다.
SELECT MEMBER_NAME,
       REVIEW_TEXT,
       DATE_FORMAT(REVIEW_DATE, '%Y-%m-%d') AS "REVIEW_DATE"
FROM   REST_REVIEW r
       JOIN MEMBER_PROFILE m
         ON r.MEMBER_ID = m.MEMBER_ID
WHERE  r.MEMBER_ID IN (SELECT MEMBER_ID
                       FROM   REST_REVIEW
                       GROUP  BY 1
                       HAVING COUNT(*) = (SELECT COUNT(*)
                                          FROM   REST_REVIEW
                                          GROUP  BY MEMBER_ID
                                          ORDER  BY 1 DESC
                                          LIMIT  1))
ORDER  BY 3,
          2;

테스트 케이스를 촘촘하게 만드는 게 생각보다 어렵겠구나 느껴지는 문제.
그와 별개로 서브쿼리를 여러 번 중첩시켜서 쓰게끔 한 건 좋다.

profile
기본기를 소홀히 하지 말자

0개의 댓글

관련 채용 정보