SQL

250602_ SQL 어려운 문제 반복 풀이

baektree 2025. 6. 2. 21:27

머릿속의 수많은 개념으로 혼란스럽다.

배운 것들은 많은데 그것들의 용도, 체계 등이 복합적이라 말 그대로 혼돈의 카오스인 것 같다.

 

구조화, 체계화를 좋아하고 자신있다 자부해왔지만 멘탈붕괴를 겪는 스스로를 보니 원통하더라.

게다가 주말 내내 반복 연습했는데도 난 여전히 모르겠다.

 

후, 그래도 해야지 어쩌겠어. 어려울수록 기본기부터 내 안에 쌓아야지, 그것들을 정리해야지.

뭐, 문제에 봉착하여 괴로워하는 것 자체가 열심히 정진하고 있음을 증명하는 일이니까.

 

- 뭐가 어려운지

- 그래서 어떻게 하면 잘 할 수 있을지

가보자고~ 

 

더보기
더보기

오늘의 주요 학습 

1. GROUP BY 사용하면

- SELECT절에 해당 컬럼이나 집계함수 꼭 써야한다. 다른거 쓰면 안된다. 이것이 바로 SQL 문법이다.

 

2. IFNULL(comlumn, 100)

- Column이 null이면 100으로 대체한다.

 

3. SUBQUERY 만들어서

- WHERE 절에 쓰거나 : 연산 단계를 나눠 할 때, 해당하는 연산값만 필터링 하기에 용이

- FROM 절에 쓸 수 있다. : 연산 단계를 나눠 할 때, 임시테이블을 미리 만들어놓고 거기서 조회하기에 용이

 

4. 자전거 대여 시 특정일 반납여부를 확인하기 위해 

- '2025-06-01' BETWEEN start_date AND end_date로 알 수 있다.

- 특정일이 포함되면 1, 아니면 0으로 신규 컬럼을 생성해 CASE WHEN으로 묶을 수 있다. 

 


 

 

250602_ SQL 어려운 문제 반복 풀이

특정일 기준 차 대여 여부 알아보기 , GROUP BY

    • 내가 겪은 풀이 방식, 왜 틀렸는지?
      • 특정 차 별로 대여기록이 여러가지 있는 것인지 몰랐다.
      SELECT CAR_ID,
              CASE WHEN START_DATE > '2022-10-16' THEN '대여중'
                  WHEN END_DATE <= '2022-10-16' THEN '대여중'
                  ELSE '대여 가능' END 'AVAILABILITY'
      FROM CAR_RENTAL_COMPANY_RENTAL_HISTORY
      ORDER BY CAR_ID DESC
      
        1. 22년도 10월 16일 기준으로 대여중인 것을 어떻게 알 수 있을까?앞으로 어떻게 하면 좋을지?
          —> 대여일과 반납일 사이에 22녀도 10월 16일이 포함되면 된다. 그러기 위해서 BETWEEN AND를 사용할 수 있다.
        2. 차 별로 22년도 10월 기준 대여중, 대여여부를 어떻게 표시할 수 있을까? 차별로 대여기록이 굉장히 많은데?
          —> 포함하면 1(대여중), 포함하지 않으면 0(대여안하는중) 한다. 예를들어 2번 차별로 1,0,1 여러개가 있을 것이다.
          —> 그리고 GROUP BY, MAX를 활용해 1이면 대여중인거고, 그렇지 않으면 대여안하는 중이다.
    • <aside> 📢
    • 나의 풀이 과정 : CASE WHEN으로 보다 간단하게 활용
      • CTE, IF, MAX 활용
      WITH A AS (SELECT CAR_ID,
             IF ('2022-10-16' BETWEEN START_DATE AND END_DATE, 1, 0) AS RENTAL
      FROM CAR_RENTAL_COMPANY_RENTAL_HISTORY
      )
      
      SELECT CAR_ID,
            CASE WHEN MAX(RENTAL) = 1 THEN '대여중'
            ELSE '대여 가능' END AS AVAILAVILITY
      FROM A
      GROUP BY CAR_ID
      ORDER BY CAR_ID DESC
      
      
      • CASE WHEN으로 보다 간단하게 활용
      -- 첫번째 풀이: 틀림
      -- 이유 :  CASE WHEN으로 묶지 않고 END 오타나서 틀림
      SELECT CAR_ID,
             MAX(CASE WHEN '2022-10-16' BETWEEN START_DATE AND END_DATE THEN 1 ELSE 0 AND)=1 THEN "대여중"
             ELSE "대여 가능" END AS AVAILAVILITY
      FROM CAR_RENTAL_COMPANY_RENTAL_HISTORY
      GROUP BY CAR_ID
      ORDER BY CAR_ID DESC
      
              
      
      -- 두번째 풀이 : 맞음
      -- 이유 :  CASE WHEN으로 묶었고 END 제대로 썼음
      SELECT CAR_ID,
             CASE 
                  WHEN MAX(CASE WHEN '2022-10-16' BETWEEN START_DATE AND END_DATE THEN 1 ELSE 0 END)=1 
                  THEN "대여중"
                  ELSE "대여 가능" 
              END AS AVAILAVILITY
      FROM CAR_RENTAL_COMPANY_RENTAL_HISTORY
      GROUP BY CAR_ID
      ORDER BY CAR_ID DESC
      
    • 다른 사람의 풀이 과정 : DISTINCT, IF 사용
      • 문제 구조화
        1. 2022 / 10 / 16 에 대여중인 CAR_ID 구하기
        2. 위의 코드를 서브쿼리로 묶기, IF를 활용해 CAR ID가 서브쿼리에 해당한다면 대여중, 그렇지 않다면 대여가능으로 출력하기
        3. DISTINCT로 CAR_ID가 여러개 나오지 않도록 조치하기
      • 문제 풀이
        • 2022 / 10 / 16 에 대여중인 CAR_ID 구하기
        SELECT CAR_ID
        FROM CAR_RENTAL_COMPANY_RENTAL_HISTORY
        WHERE START_DATE <= '2022-10-16' AND
        			END_DATE >= '2022-10-16'
        
        • 위의 코드를 서브쿼리로 묶어 대여중인 CAR _ID에 해당한다면 대여중, 아니면 대여가능을 출력하는 IF 문을 SELECT 문에 넣기
        • DISTINCT로 CAR_ID가 여러개 나오지 않도록 조치하기
        SELECT DISTINCT CAR_ID,
        			IF (CAR_ID IN (SELECT CAR_ID
        					FROM CAR_RENTAL_COMPANY_RENTAL_HISTORY
        					WHERE START_DATE <= '2022-10-16' AND
        								END_DATE >= '2022-10-16'), '대여중', '대여 가능') AS AVAILABILITY
        FROM CAR_RENTAL_COMPANY_RENTAL_HISTORY 
        ORDER BY CAR_ID DESC 
        
    • 풀이 핵심
      • 22/10/16일 기준 대여중인 쿼리문 만들기 BETWEEN AND WHRER
      • -- 1. 해당일이 대여일과 반납일 사이에 포함되어 있다면 대여중인 것이다. ‘2022-10-16’ BETWEEN START_DATE AND END_DATE
      • -- 2 대여일이 22/10/16보다 작거나 같고 , 반납일이 22/10/16보다 크거나 같으면 대여중인 것이다. WHERE START_DATE <= '2022-10-16' AND END_DATE >= '2022-10-16'
      • 대여중, 대여아닌 것 구분하기
      • CASE WHEN ~~ -- 참고 CASE WHEN 안에 또 CASE WHEN을 쓸 수 있다.

특정 조건을 만족하는 물고기별 수와 최대 길이 구하기 , SUBQUERY, GROUP BY

  • 문제
  • FISH_INFO에서 평균 길이가 33cm 이상인 물고기들을 종류별로 분류하여 잡은 수, 최대 길이, 물고기의 종류를 출력하는 SQL문을 작성해주세요. 결과는 물고기 종류에 대해 오름차순으로 정렬해주시고, 10cm이하의 물고기들은 10cm로 취급하여 평균 길이를 구해주세요.
  • 문제 구조화
    1. 10cm 이하인 물고기들은 10cm로 출력되도록 함.
    2. 연산에 필요한 fish_type, new_length가 출력되게 함
    3. 위의 서브쿼리 fish_type별로 잡은 수 , 최대길이, 종류를 출력함
      이때 함수는 count, max를 사용함
    4. 단 물고기 타입별로 평균 길이가 33이상인 것만 필터링함 avg(new_length)≥ 33
    5. 오름차순 정렬 order by fish_type
    6. 컬럼명 별칭 : 컬럼명은 물고기의 종류 'FISH_TYPE', 잡은 수 'FISH_COUNT', 최대 길이 'MAX_LENGTH'로 해주세요.
  • 풀이
    • 풀이 핵심그것을 임시테이블로 쓴다.
    • 그런 다음 group by를 한다.
    • 서브쿼리를 만들어놓고
    SELECT COUNT(FISH_TYPE) AS FISH_COUNT ,
    			MAX(NEW_LENGTH) AS MAX_LENGTH,
    			FISH_TYPE
    FROM 
    (
    SELECT FISH_TYPE,
    			IF(LENGTH IS NULL, 10, LENGTH) AS NEW_LENGTH
    FROM FISH_INFO
    ) A
    GROUP BY FISH_TYPE
    HAVING AVG(NEW_LENGTH) >= 33 
    ORDER BY FISH_TYPE
    
  • 다른풀이 IFNULL 사용
    • IFNULL 이란?
      • IFNULL(length, 10) : length가 null 이면 10으로 대체
    SELECT COUNT(FISH_TYPE) AS FISH_COUNT,
    				MAX(LENGTH) AS MAX_LENGTH,
    				FISH_TYPE
    FROM FISH_INFO
    GROUP BY FISH_TYPE
    HAVING AVG(IFNULL(LENGTH, 10)) >= 33 
    ORDER BY FISH_TYPE
    

물고기 종류별 대어 찾기 SUBQUERY, GROUP BY, WHERE 절 IN