처음 답안(오답)
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 컬럼에는 팔린 갯수가 나와 있으니 두 개를 곱하면 될 줄 알았다. 곱하는 과정에 문제가 있는 것 같아서 다른 방법을 생각해 보았다.
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;
정답!
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로 굳이 처리해줬는데, 번거로운 방법이었다.
두 테이블에서 동일한 고유키(또는 조인 조건 컬럼)를 기준으로 묶되,
양쪽 테이블 모두 해당 키에 데이터가 있을 때만 그 행을 결과에 포함하는 방식
핵심은 만원 단위의 가격대 별로 상품을 나누는 PRICE_GROUP 칼럼을 만들 것.
처음에는 CASE WHEN 0<PRICE<=10000 THEN 0 과 같이 일일이 조건을 설정했는데, 생각해보니 PRICE 컬럼의 가격 범위를 모르니 적절하지 않았다.
그럼 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(*) | 모든 행을 무조건 카운트 (NULL 포함 여부 상관 없음) |
COUNT(PRODUCT_ID) | PRODUCT_ID 컬럼이 NULL이 아닐 때만 카운트 |
반복문을 써야 된다는 것, 짝수/홀수 조건까진 알겠는데 '작업을 몇 번이나 반복해야 하는지 반환하는 함수'를 작성하는 것, '작업을 500번 반복할 때까지 1이 되지 않는다면 -1을 반환할 것'이라는 조건이 걸림돌이었다.
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
질문하기를 참고하여 코드를 작성했는데, 오답이었다. 아무래도 힌트를 보고 적용하는 과정에서 오류가 생긴 모양이다.
if와 else가 좀 더 깔끔하게 나뉘었으면 좋겠음. 처음에 입력한 값이 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