240715

Gi Woon Lee·2024년 7월 15일
0

TIL

목록 보기
17/78

SQL

70번. 그룹별 조건에 맞는 식당 목록 출력하기

WITH MOST AS (
    SELECT MEMBER_ID, COUNT(*) AS CNT
    FROM REST_REVIEW
    GROUP BY MEMBER_ID
    ORDER BY CNT DESC
    LIMIT 1
)
SELECT P.MEMBER_NAME, 
       R.REVIEW_TEXT, 
       DATE_FORMAT(R.REVIEW_DATE, '%Y-%m-%d') AS REVIEW_DATE
FROM MEMBER_PROFILE P
JOIN REST_REVIEW R ON P.MEMBER_ID = R.MEMBER_ID
JOIN MOST M ON R.MEMBER_ID = M.MEMBER_ID
ORDER BY R.REVIEW_DATE ASC, R.REVIEW_TEXT ASC;
#틀린 이유 1. WITH 절 SELECT문에서 GROUP BY로 집계하지 않는 REVIEW_TEXT를 반환시켰다.
#         2. LIMIT 1이 아닌 LIMIT 3을 사용했다.
#         3. 문제를 잘 안읽고 ASC를 DESC로 작성했다. 
#         4. GROUP BY를 사용한 집계함수 결과에 대한 필터링은 HAVING을 사용해야만 한다. 

첫 with문 사용. 언젠가는 알아야 할 개념을 이악물고 외면하다가 처음 사용해봤다. 막상 써보니 별 거 아니라서 시시했다. 틀린 이유를 복습하면서 자세히 복기하자.

71번. 오프라인/온라인 판매 데이터 통합하기

SELECT DATE_FORMAT(SALES_DATE, '%Y-%m-%d')SALES_DATE, 
	   PRODUCT_ID, USER_ID, SALES_AMOUNT
FROM 
(SELECT SALES_DATE, PRODUCT_ID, USER_ID, SALES_AMOUNT
FROM ONLINE_SALE
WHERE SALES_DATE LIKE '2022-03%'
UNION
SELECT SALES_DATE, PRODUCT_ID, NULL, SALES_AMOUNT
FROM OFFLINE_SALE
WHERE SALES_DATE LIKE '2022-03%') A
ORDER BY 1,2,3

UNION을 처음 사용한 쿼리.

  • JOIN: 관계가 있어야 한다. 두 테이블에 각각 존재하는 '다른 의미를 가지는' 날짜 데이터끼리 JOIN을 해 봐야 의미가 없다. '같은 내용의 행 데이터를 같는 횡결합

  • UNION: 독립된 두 테이블이지만 '동일한 형식의 열 칼럼'을 갖는 종결합
    이 때, 1 UNION 2 테이블에서 2테이블의 칼럼이 하나 없더라도, SELECT 칼럼 자리에 을 넣으면 1테이블 칼럼명을 그대로 쓰되 2테이블의 이 모든 행에 채워진다.

72번. 조건에 맞는 중고거래 댓글 조회

SELECT B.TITLE, B.BOARD_ID, R.REPLY_ID, R.WRITER_ID, R.CONTENTS, 
       DATE_FORMAT(R.CREATED_DATE, '%Y-%m-%d') CREATED_DATE
FROM USED_GOODS_REPLY R JOIN USED_GOODS_BOARD B
ON R.BOARD_ID = B.BOARD_ID
WHERE B.CREATED_DATE LIKE '2022-10%'
ORDER BY R.CREATED_DATE, B.TITLE

73번. 입양 시각 구하기(2)(재귀CTE)

WITH RECURSIVE CREATED_HOURS AS ( #  'WITH RECURSIVE' 까지가 재귀CTE 선언 함수
    -- 앵커 멤버: 0을 반환
    SELECT 0 AS HOUR
    UNION ALL
    -- 재귀 멤버: number에 1을 더해가면서 24 이하까지 
    SELECT HOUR + 1
    FROM CREATED_HOURS
    WHERE HOUR < 23 # SELECT에서 + 1 이 있으니까 23까지 반환한다. 
)
SELECT C.HOUR,
       CASE WHEN COUNT IS NULL THEN '0' # NULL 값에 '0' 을 넣어주고 
            ELSE COUNT END COUNT        # 나머지 값은 그대로 소환
FROM CREATED_HOURS C 
LEFT JOIN   # 재귀CTE로 생성한 0~23 숫자를 모두 살려야 하기에 LEFT JOIN
    (SELECT HOUR(DATETIME) HOUR, COUNT(ANIMAL_ID) COUNT 
     FROM ANIMAL_OUTS 
     GROUP BY HOUR(DATETIME)) A 
ON C.HOUR = A.HOUR

Python

27번 핸드폰 번호 가리기

def solution(phone_number):
    length = len(phone_number) - 4      # 길이 변수 생성
    masking_part = '*' * length         # 마스킹 파트 변수 생성
    last_four_digits = phone_number[-4:]        # 뒤 4자리 변수 생성
    masked_number = masking_part + last_four_digits     # 마스킹 파트 + 뒤 4자리를 통해 마스킹 완료된 값 반환
    return masked_number

indexing, 문자열 사칙연산 같은 마법카드를 몇 장 사용하면 다음과 같은 최적화 코드가 나온다.

def hide_numbers(phone_number):
    return ('*'*(len(phone_number)-4)) + phone_number[-4:]

나도 개념들이 머리에 자리잡혀 이렇게 간단하게 코드를 짤 수 있기를..

28번 없는 숫자 더하기

  • 내가 작성한 오답..진심 답없음 ㅋㅋ
def solution(numbers):
    for num in numbers:         # 이러면 안돼...문제에 1~10에 없는 값을 number 로 준다고 하잖아.
        if num != range(1:10):  # range함수 구조: range(시작,미만값,구간) 이다
            answer = print(sum(num)) # sum함수는 literable 객체에만 사용 가능하다.  
    return answer   

총체적 난국인 나의 코드를 하나씩 짚어보자.
1. 우선 sum()함수는 literable 객체에만 사용이 가능하다.
2. range() 의 구조는 range(시작값, 미만값, 구간) 이다. ' : '은 대체 어디서 온 걸까.
3. 멤버십 검증을 위해 멤버십 연산자 in or not in 을 사용해야 한다. =, !=은 비교 연산자로 두 값을 비교하는 역할이다.


  • 논리적으로 풀어낸 정답
def solution(numbers):
    total_number = sum(range(10))
    given_number = sum(numbers)
    answer = total_number - given_number
    return answer

말 그대로 직관적이며 이해가 쉽지만 변수가 많아 효율적이진 않은 것 같다.


  • for 반복문을 통한 정답
def solution(numbers):
    answer = 0
    for i in range(1,10):
        if i not in numbers:
            answer += i
    return answer

가장 흔하게 쓰이는 구조이다. 이 구조를 디폴트로 생각할 줄 알아야겠다.
answer = 0 변수 초기화, range()를 통한 구간 생성, 멤버십 연산자 등의 개념을 기억하자.


  • 간단한 코드
def solution(numbers):
    answer = sum(range(10)) - sum(numbers)
    return answer

머리가 좋으면 손가락이 편하다.

29번. 제일 작은 수 제거하기

  • 나의 오답
def solution(arr):
    min_value = min(arr)
    answer = arr.remove(min_value) # .remove() 메서드는 arr 리스트를 직접 수정하기 때문에 answer에 아무것도 반환하지 않는다. 
    if len(arr) < 2:
        return [-1]
    else:
        return answer

내가 answer 변수에 remove()메서드로 최소값을 제거한 arr리스트를 담으려고 한 것에서 오류가 발생했다.

리스트 내 값을 삭제하는 .remove(값)메서드는 리스트를 직접 수정하기 때문에 아무것도 반환하지 않느다.
따라서 .remove()메서드의 결과를 저장하는 answer 또한 null값을 가지게 된다.

  • 정답 코드
def solution(arr):
    min_value = min(arr)
    arr.remove(min_value) 
    if len(arr) < 2:
        return [-1]
    else:
        return arr

30번. 가운데 글자 가져오기

def solution(s):
    answer = 0
    if len(s) % 2 != 0:
        answer = s[len(s)//2]
    else:
        answer = s[len(s)//2-1:len(s)//2+1]
    return answer

indexing 문제다. 짝수와 홀수의 경우로 나눈 뒤 인덱스 범위를 사용할 수 있는지 확인하는 문제였음. list[이상,미만,구간]을 잘 생각해서 비슷한 문제가 나오면 적극 활용하자.

  • 여기서는 왜 answer = 0 초기화를 안해도 되는가?
    answer: 조건문if-else에 의해 항상 answer값이 할당되기 때문이다.

31번. 수박수박수박수박수박수?

  • 나의 정답
def solution(n):
    if n % 2 == 0:
        answer = '수박'*(n//2)
    else:
        answer = '수박'*(n//2) + '수'
    return answer
  • 다른 사람의 섹시한 정답

개념

CTE (일반CTE, 재귀CTE)

WITH
  cte1 AS (SELECT a, b FROM table1),
  cte2 AS (SELECT c, d FROM table2)
SELECT b, d FROM cte1 JOIN cte2
WHERE cte1.a = cte2.c;

0개의 댓글