[내일배움캠프] SQL/Python 코드카타

sleekstar·2025년 5월 28일

SQL 코드카타

문제 1.

카테고리 별 도서 판매량 집계하기

처음 답안(오답)

SELECT 
    B.CATEGORY,
    COUNT(*) * S.SALES TOTAL_SALES
FROM BOOK B LEFT JOIN BOOK_SALES S
ON B.BOOK_ID = S.BOOK_ID
WHERE S.SALES_DATE LIKE '%2022-01%'
GROUP BY 1
ORDER BY 1 ASC;

뭐가 문제지?
원래 아이디어는 CATEGORY 갯수를 세고, SALES 컬럼에는 팔린 갯수가 나와 있으니 두 개를 곱하면 될 줄 알았다. 곱하는 과정에 문제가 있는 것 같아서 다른 방법을 생각해 보았다.

IDEA

CATEGORY와 대응되는BOOK_ID, 그게 몇 개 팔렸는지 나타내는 SALES
SALES의 타입은 INTEGER
곱하기가 아니라 더하기인가?

수정 답안

SELECT 
    B.CATEGORY,
    SUM(S.SALES) TOTAL_SALES
FROM BOOK B LEFT JOIN BOOK_SALES S
ON B.BOOK_ID = S.BOOK_ID
WHERE S.SALES_DATE LIKE '%2022-01%'
GROUP BY B.CATEGORY
ORDER BY B.CATEGORY ASC;

정답!

문제 2.

오랜 기간 보호한 동물(2)

SELECT
    I.ANIMAL_ID,
    I.NAME
FROM ANIMAL_INS I 
INNER JOIN ANIMAL_OUTS O
    ON I.ANIMAL_ID = O.ANIMAL_ID
ORDER BY DATEDIFF(O.DATETIME, I.DATETIME) DESC
LIMIT 2;

처음에 DATEDIFF 의 STARTDATE 부분에 I.DATETIME을 넣고 뒤에 O.DATETIME을 넣었더니 값이 음수가 나와서 순서를 바꿨다. 앞에서 뒤를 빼니까 기간을 구하고 싶으면 순서를 잘 생각해야 할 것 같다.

이번 문제에서는 INNER JOIN을 생각하는 게 포인트였다.
처음에 LEFT JOIN으로 하고, 값이 없는 부분을 WHERE~IS NOT NULL로 굳이 처리해줬는데, 번거로운 방법이었다.

INNER JOIN이란

두 테이블에서 동일한 고유키(또는 조인 조건 컬럼)를 기준으로 묶되,
양쪽 테이블 모두 해당 키에 데이터가 있을 때만 그 행을 결과에 포함하는 방식

문제 3.

가격대 별 상품 개수 구하기

PROBLEM

핵심은 만원 단위의 가격대 별로 상품을 나누는 PRICE_GROUP 칼럼을 만들 것.
처음에는 CASE WHEN 0<PRICE<=10000 THEN 0 과 같이 일일이 조건을 설정했는데, 생각해보니 PRICE 컬럼의 가격 범위를 모르니 적절하지 않았다.

TRY

그럼 PRICE를 10000으로 나눈 몫을 반환하면 어떨까?
파이썬에서는 이럴 때 PRICE // 10000 을 하면 되지만, SQL에선 되지 않았다.
그래서 소수점 밑의 값을 버리는 FLOOR를 적용.
ROUNG((PRICE / 10000), 0))도 생각해 봤지만 이건 반올림이라 FLOOR가 맞을 듯하다.
그 값에 10000을 다시 곱하면 몇만원대인지 알 수 있다.

정답

SELECT 
    FLOOR(PRICE / 10000) * 10000 AS PRICE_GROUP,
    COUNT(PRODUCT_ID) AS PRODUCTS     
    # COUNT(*) 로 대체 가능
FROM PRODUCT
GROUP BY PRICE_GROUP
ORDER BY PRICE_GROUP ASC;

COUNT(*)과 COUNT(컬럼명)

구문의미
COUNT(*)모든 행을 무조건 카운트 (NULL 포함 여부 상관 없음)
COUNT(PRODUCT_ID)PRODUCT_ID 컬럼이 NULL이 아닐 때만 카운트

알고리즘 코드카타

문제 1.

콜라츠 추측

반복문을 써야 된다는 것, 짝수/홀수 조건까진 알겠는데 '작업을 몇 번이나 반복해야 하는지 반환하는 함수'를 작성하는 것, '작업을 500번 반복할 때까지 1이 되지 않는다면 -1을 반환할 것'이라는 조건이 걸림돌이었다.

idea

range를 그동안 썼으니까 이번에도...?

처음 답안(오답)

def solution(num):
    # 500번 반복
    for i in range(500):
        # 짝수라면 2로 나누기
        if num % 2 == 0: 
            num = num/2
        # 그렇지 않다면(홀수라면) 3 곱하고 1 더하기
        else:
            num = (num*3)+1 
        # 반복하다가 num==1이 되면 시행 횟수 리턴
        if num == 1:
            return i+1
    # 500번 반복문을 탈출한다면 -1 리턴
    return -1

problem

질문하기를 참고하여 코드를 작성했는데, 오답이었다. 아무래도 힌트를 보고 적용하는 과정에서 오류가 생긴 모양이다.

try

ifelse가 좀 더 깔끔하게 나뉘었으면 좋겠음. 처음에 입력한 값이 1일 수도 있으니 if num==1: return i+1를 맨 앞으로 옮기는 게 좋아보임.

그리고 문제에서 횟수를 구하라곤 했지만, 0도 리턴이 가능하니 i+1이 아니라 그냥 i를 리턴해야겠다.

또, num = num / 2에서 정수 나눗셈인 num // 2로 바꿔주면 더 깔끔할 것 같다.

수정 답안(정답)

def solution(num):
    for i in range(500):
        if num == 1:
            return i
        if num % 2 == 0:
            num = num // 2  
        else:
            num = num * 3 + 1
    return -1
profile
기록용

0개의 댓글