티스토리 뷰

SQL 코드카타

Q125. 1327. List the Products Ordered in a Period

1. 문제 링크: https://leetcode.com/problems/list-the-products-ordered-in-a-period/description/

2. 정답 코드:

SELECT
    p.product_name,
    SUM(o.unit) as unit
FROM Orders as o
JOIN Products as p
  ON p.product_id = o.product_id
WHERE SUBSTR(o.order_date, 1, 7) = '2020-02'
GROUP BY p.product_name
HAVING SUM(o.unit) >= 100

 

Q92. 1251. Average Selling Price

1. 문제 링크: https://leetcode.com/problems/average-selling-price/description/

2. 정답 코드:

SELECT
    p.product_id,
    IFNULL(ROUND((SUM(p.price*u.units) / SUM(u.units)), 2), 0) as average_price
FROM Prices as p
LEFT JOIN UnitsSold as u
  ON p.product_id = u.product_id
  AND u.purchase_date >= p.start_date
  AND u.purchase_date <= p.end_date
GROUP BY p.product_id

평균 단가 공식

 

 

Q101. 1070. Product Sales Analysis III

1. 문제 링크: https://leetcode.com/problems/product-sales-analysis-iii/

2. 정답 코드:

SELECT
    product_id,
    year as first_year,
    quantity,
    price
FROM Sales
WHERE (product_id, year) IN (
    SELECT
        product_id,
        MIN(year)
    FROM Sales
    GROUP BY product_id
)

3. 오류 상황: MIN(year)을 first_year로 나타내는데 원하는 행만 가져올 수가 없음

4. 시도 방법: 왜 원하는 결과대로 나오지 않는지 생성형 AI에게 힌트를 물어봄

5. 최종 문제 해결 방법: 서브쿼리를 사용해서 product_id별로 MIN(year)에 해당하는 행만 WHERE 조건을 줘서 가져온다! 이때 두가지 컬럼이 모두 조건을 만족해야 하므로, 괄호를 사용해서 WHERE (product_id, year) IN (서브쿼리) 로 작성한다!!

 

Q105. 1045. Customers Who Bought All Products

1. 문제 링크: https://leetcode.com/problems/customers-who-bought-all-products/description/

2. 정답 코드:

SELECT customer_id
FROM Customer
GROUP BY customer_id
HAVING COUNT(DISTINCT product_key) = (SELECT COUNT(*) FROM Product)
Customer 테이블에서의 product_key 개수 = Product 테이블에서의 product_key 개수를 만족하는 customer_id 찾기
두 테이블을 JOIN할 필요는 없고, customer_id 별로 GROUP BY를 한 후에 HAVING 절에서 COUNT를 사용해 조건을 설정해주면 된다! 여기서 서브쿼리를 사용해줘야 하는데, 서브쿼리를 사용할 때는 무조건 앞뒤로 괄호가 있어야 한다.

 

Q106. 1731. The Number of Employees Which Report to Each Employee

1. 문제 링크: https://leetcode.com/problems/the-number-of-employees-which-report-to-each-employee/description/

2. 정답 코드:

SELECT
    m.employee_id,
    m.name,
    COUNT(e.reports_to) as reports_count,
    ROUND(AVG(e.age), 0) as average_age
FROM Employees as m
JOIN Employees as e
  ON m.employee_id = e.reports_to
GROUP BY m.employee_id, m.name
ORDER BY m.employee_id;

3. 오류 상황: reports_count와 average_age가 계산이 안됨

4. 시도 방법: employee_id와 reports_to를 어떻게 매칭할지 생성형 AI에게 힌트를 물어봄

5. 최종 문제 해결 방법: 셀프 조인을 사용해서 하나는 매니저 테이블, 하나는 직원 테이블로 만들어서 m.employee_id = e.reports_to 로 조건을 걸어준다!


Python 코드카타 (https://github.com/heeso0908/codekata.git)

Q31. 수박수박수박수박수박수?

1. 문제 링크: https://school.programmers.co.kr/learn/courses/30/lessons/12922

2. 정답 코드:

def solution(n):
    answer = ''
    for i in range(n) :
        if i % 2 == 0 :
            answer += '수'
        else :
            answer += '박'
    return answer

 

Q32. 내적

1. 문제 링크: https://school.programmers.co.kr/learn/courses/30/lessons/70128

2. 정답 코드:

def solution(a, b):
    result = 0
    for i in range(len(a)) :
        result += a[i] * b[i]
    return result

 

Q33. 약수의 개수와 덧셈 ★어려움★

1. 문제 링크: https://school.programmers.co.kr/learn/courses/30/lessons/77884

2. 정답 코드:

def solution(left, right):
    answer = 0
    for i in range(left, right+1) :
        if int(i**0.5) == i**0.5 :
            answer -= i
        else :
            answer += i
    return answer

3. 오류 상황: 약수 개수가 홀수일 때는 빼주고, 짝수일 때는 더해줘야 하는데 for 문을 사용하니 원하지 않는 수까지 더해짐

4. 시도 방법: 해결할 방법을 모르겠어서 생성형 AI에게 물어봄

5. 최종 문제 해결 방법: for 문을 사용하면 코드가 복잡해지기도 하고, 이해도 잘 되지 않아서 if 문으로 변경해서 사용

제곱수를 찾는 방법을 아래와 같이 변경함!

약수의 개수가 홀수인 수 == 제곱수 (ex. 25의 약수 : 1, 5, 25)  
제곱수를 찾으려면 제곱근이 정수인지 확인하면 됨 → int(i**0.5) == i**0.5 (ex. int(5.0) == 5.0)
def solution(left, right):
    answer = 0
    for i in range(left, right+1) :
        for j in range(1, i) :
            if j**2 == i :
                answer -= i
            else :
                answer += i
    return answer

# 이전에 작성한 코드

 

Q34. 문자열 내림차순으로 배치하기

1. 문제 링크: https://school.programmers.co.kr/learn/courses/30/lessons/12917

2. 정답 코드:

def solution(s):
    answer = "".join(sorted(s, reverse=True))
    return answer

3. 오류 상황: sort인지 sorted인지 헷갈림

4. 시도 방법: 해결할 방법을 모르겠어서 생성형 AI에게 물어봄

5. 최종 문제 해결 방법: 텍스트를 정렬하려면 아래 코드를 세트로 외워두면 편하다!

문자열 내림차순(역순)으로 정렬하는 방법
"".join(sorted(문자열, reverse = True))
  • 리스트.sort() 메소드 (명단 자체를 수정하기) : 원래 리스트의 순서가 완전히 바뀜, 결과값(return)이 없음
  • sorted(리스트) 함수 (새로운 명단 만들기) : 원래 리스트는 건드리지 않음, 정렬된 새로운 리스트를 결과로 줌

 

Q35. 부족한 금액 계산하기

1. 문제 링크: https://school.programmers.co.kr/learn/courses/30/lessons/82612

2. 정답 코드:

def solution(price, money, count):
    paid = 0
    for i in range(1, count+1) :
        paid += price * i
    
    total = money - paid
    if total >= 0 :
        return 0
    else :
        return paid - money
내야하는 금액은 paid라는 변수에 for 문으로 받아서 저장하고,
total = money - paid 로 계산하여 total이 0 이상이면 0을 반환
그렇지 않으면(total이 음수이면) 부족한 금액(paid - money)을 반환

라이브 세션) 데이터 전처리/시각화 3일차 - [GroupBy · 결합 · 시간/문자열 · apply/map 마스터(요약테이블 2개 만들기)]

isinstance(x, bool)

: x가 boolean 타입인지? 맞으면 True 반환, 아니면 False 반환하는 함수

def to_bool(x):
    if isinstance(x, bool):
        return x
    x = str(x).strip().lower()
    return x in ["true", "1", "yes", "y"]

여기서 마지막 줄 return x in ["true""1""yes""y"]

x가 ["true", "1", "yes", "y"] 중에 들어있다면

즉,  x in ["true""1""yes""y"] 자체가 True 이므로 결과적으로 True를 반환하게 된다!


np.where(조건, 참일 때 값, 거짓일 때 값)

: if문은 한 번에 딱 하나의 숫자만 검사할 수 있는 반면, np.where는 수만 개의 데이터가 든 리스트(배열)를 한 방에 처리 가능!

df["sales"] = np.where(df["paid"], df["price"] * df["qty"], 0)

GroupBy + 집계함수(Aggregation)

여기서 agg는 aggregation이 맞긴한데, 의미는 약간 다른게 groupby 사용해서 뒤에 집계함수(sum, count, ...)를 여러 개 사용할 수 있다는 의미의 속성이고, 뒤에 실제로 집계함수(sum, count, ...)를 사용한다!

store_summary = df.groupby("store").agg(
    total_sales=("sales","sum"),
    orders=("order_id","count"),
    paid_rate=("paid","mean")
).reset_index()

 

1. 한 가지만 궁금할 때 (기본형)

특정 그룹별로 한 가지 통계만 보고 싶을 때 사용

# 가게(store)별로 매출(sales)의 '합계'만 딱 보여줘!
df.groupby("store")["sales"].sum()

 

2. 여러 가지를 동시에 보고 싶을 때 (리스트형)

매출의 합계도 궁금하고, 평균이랑 개수도 한꺼번에 보고 싶을 때 사용

# 리스트 [ ] 안에 원하는 함수 이름을 써주면 된다
summary = df.groupby("store")["sales"].agg(["sum", "mean", "count"])
  • 결과표에 자동으로 sum, mean, count라는 제목이 붙어서 나옴

3. 컬럼마다 다른 계산을 하고 싶을 때 (딕셔너리형)

"매출은 합계를 내고, 평점은 평균을 내줘!" 처럼 컬럼마다 요구사항이 다를 때, 중괄호 { } 사용

summary = df.groupby("store").agg({
    "sales": "sum",      # 매출은 다 더하고
    "rating": "mean",    # 별점은 평균 내고
    "order_id": "count"  # 주문번호는 개수를 세어라
})

 

4. 결과에 예쁜 이름을 붙여주고 싶을 때 (Named Aggregation)

계산과 동시에 결과 컬럼의 이름을 직접 정할 수 있음

store_summary = df.groupby("store").agg(
    총매출=("sales", "sum"),
    평균매출=("sales", "mean"),
    주문건수=("order_id", "count")
)

 

⚠️ 주의사항: reset_index()

agg를 쓰고 나면 그룹으로 묶었던 '가게 이름'이 표의 제목처럼 위로 올라가 버려서 이걸 다시 일반 데이터 칸으로 내려주기 위해 습관적으로 끝에 .reset_index()를 붙여주는 것이 좋다!


case → 대/소문자 구분!

member_df = df[df["note"].str.contains("member", case=False, na=False)]

case = False 이면, 대/소문자 구분 안하겠단 의미! 기본 값은 구분 O


12와 2의 int / string 비교 차이?

1. 숫자(int) 비교 : 누가 더 큰지?

우리가 수학 시간에 배우는 수직선에서의 크기 비교

  • 비교 방식 : 전체 값을 통째로 비교
  • 결과 : 12 > 2 이므로 12가 더 큼
  • 컴퓨터 내부 : 십진수 12와 2를 이진수로 바꿔서 양(Quantity)을 비교

2. 문자(string) 비교 : 누가 사전에 먼저 나오나?

영어 사전이나 국어 사전에서 단어를 찾는 것과 같다!

  • 비교 방식 : 맨 앞글자부터 한 글자씩 차례대로 비교
  • 결과 : "12" < "2" 이므로 "2"가 더 크다고 판단
  • 이유 : 
    • 첫 번째 글자를 먼저 비교: "1" vs "2"3. 뒤에 뭐가 오든 상관없이 첫 글자에서 승부가 났으므로 "2"가 더 크다고 생각
    • "1"이 "2"보다 사전 순서(아스키 코드 번호)가 앞

+ join 할 때 primary key 아니어도 조인 가능하긴 하지만, 그러면 테이블이 더러워짐

테이블이 더러워진다 = 내가 통제할 수 없는 중복 행이 생성되어 데이터의 정밀도가 깨지는 상태

→ 가능하면 Unique한 키를 기준으로 조인하는 것이 데이터의 청결(무결성)을 유지하는 가장 좋은 방법!


오늘은 파이썬 데이터 전처리를 다루는 마지막 날이었다.
물론 내일 시각화 과정을 진행하면서도 전처리를 다시 다루게 되겠지만, 3일 동안 배운 전처리 내용이 기초 프로젝트 수준이라고 하셔서 충분한 복습이 필요하다고 느꼈다.
이전에 봤던 파이썬 전처리/시각화 관련 도서를 활용해, 평일에도 자투리 시간을 이용해 전처리 과정에 조금씩 익숙해지도록 해봐야겠다.
요즘 들어 집중력이 흐트러지는 순간이 잦아지는 것 같아, 학습 리듬을 다시 잘 잡는 데에도 신경 써야 할 것 같다.
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2026/05   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31
글 보관함