Today I Learn
: SQL 코드카타, 수업날 복습, 문풀날 연습문제 / 심화문제
- SQL 코드카타
- 문제 1
1. 문제 링크: https://school.programmers.co.kr/learn/courses/30/lessons/157342
2. 정답 코드:
select
car_id,
round(avg(datediff(end_date,start_date)+1),1) as average_duration
from car_rental_company_rental_history
group by car_id
having average_duration >= 7
order by average_duration desc, car_id desc
with days as (
select
car_id,
datediff(end_date,start_date)+1 as duration
from car_rental_company_rental_history
)
select
car_id,
round(avg(duration),1) as average_duration
from days
group by car_id
having round(avg(duration),1) >= 7
order by average_duration desc, car_id desc
- 문제 2
1. 문제 링크: https://school.programmers.co.kr/learn/courses/30/lessons/77487
2. 정답 코드:
select id, name, host_id
from places
where host_id in (
select host_id
from places
group by host_id
having count(*) >= 2)
order by id
select id, name, host_id
from places pl
where exists (
select 1
from places p
where p.host_id = pl.host_id
group by host_id
having count(*) >= 2)
order by id
with counted as (
select id, name, host_id, count(*) over (partition by host_id) as cnt
from places
)
select id, name, host_id
from counted
where cnt >= 2
order by id
- 시간복잡도 최적화
- 윈도우함수를 사용함으로써 테이블을 두번 읽지 않음
- 문제 3
1. 문제 링크: https://school.programmers.co.kr/learn/courses/30/lessons/62284
2. 정답 코드:
select distinct cart_id
from cart_products c
where exists (
select 1
from cart_products c2
where c.cart_id = c2.cart_id
and name = 'Milk') and
exists (
select 1
from cart_products c3
where c.cart_id = c3.cart_id
and name = 'Yogurt')
order by cart_id
select cart_id
from cart_products
where name in ('Milk','Yogurt')
group by cart_id
having count(distinct name) = 2
order by cart_id
- where name in (...) 조건을 통해 필요한 행들만 먼저 골라낸 뒤 단 한번의 group by 연산으로 끝남
- I/O 비용을 대폭 줄임
- 문제 4
1. 문제 링크: https://school.programmers.co.kr/learn/courses/30/lessons/133027
2. 정답 코드:
with july_icecream as (
select flavor, sum(total_order) as total_order
from july
group by flavor
)
select fh.flavor
from first_half fh
join july_icecream ji
on fh.flavor = ji.flavor
order by fh.total_order + ji.total_order desc
limit 3
- first_half에 주문되었지만 july에 주문되지 않은 flavor이 있을 수도 있으니
- inner join 대신 left join 사용
with july_icecream as (
select flavor, sum(total_order) as total_order
from july
group by flavor
)
select fh.flavor
from first_half fh
left join july_icecream ji # july에 없는 flavor 까지 포함
on fh.flavor = ji.flavor
order by fh.total_order + ifnull(ji.total_order,0) desc
limit 3
- first_half에 없었는데 july에 생긴 flavor이라면
- left join을 했을 때 누락 될 수 있음.
- → 열 타입이 모두 같기 때문에 union all 을 사용하면 누락된 값 없이 모든 행을 조회할 수 있
select flavor
from (
select flavor, total_order from first_half
union all
select flavor, total_order from july
) as combined
group by flavor
order by sum(total_order) desc
limit 3;
- 문제 5
1. 문제 링크: https://school.programmers.co.kr/learn/courses/30/lessons/131537
2. 정답 코드:
select *
from (
select date_format(sales_date,'%Y-%m-%d') as sales_date, product_id, user_id, sales_amount
from online_sale
where sales_date >= '2022-03-01' and sales_date < '2022-04-01'
union all
select date_format(sales_date,'%Y-%m-%d'), product_id, NULL, sales_amount
from offline_sale
where sales_date >= '2022-03-01' and sales_date < '2022-04-01'
) as combined
order by sales_date asc, product_id asc, user_id asc
- 그동안 썼던 where sales_date like '2022-03%' 은 date 타입일때 문자열 패턴 매칭 like 를 수행하며 효율적인 실행을 하지 못할 수 있음
- 따라서 범위를 정확히 지정해주는 것이 중요한데,
- between '2022-03-01' and '2022-03-31'을 할 경우, timestamp나 datetime 타입일 때 2022-03-31 00:00:00 까지만 포함하는 범위라서 완벽히 포괄하지 못함
- → '반열린 구간'을 통해 완벽하게 포괄할 수 있음!
- 문제 6
1. 문제 링크: https://leetcode.com/problems/recyclable-and-low-fat-products/description/
2. 정답 코드:
select product_id
from products
where low_fats = 'Y' and recyclable = 'Y'
- 문제 7
1. 문제 링크: https://leetcode.com/problems/find-customer-referee/submissions/1883754448/
2. 정답 코드:
select name
from Customer
where referee_id != 2 or referee_id is null
- 문제 8
1. 문제 링크: https://leetcode.com/problems/big-countries/
2. 정답 코드:
select name, population, area
from World
where area >= 3000000 or population >= 25000000
- 문제 9
1. 문제 링크: https://leetcode.com/problems/article-views-i/
2. 정답 코드:
select distinct author_id as id
from Views
where author_id = viewer_id
order by id
- 문제 10
1. 문제 링크: https://leetcode.com/problems/invalid-tweets/submissions/1883760494/
2. 정답 코드:
select tweet_id
from Tweets
where length(content) > 15
- 문제 11
1. 문제 링크: https://leetcode.com/problems/not-boring-movies/description/
2. 정답 코드:
select id, movie, description, rating
from Cinema
where id % 2 = 1 and description != "boring"
order by rating desc
- 문제 12
1. 문제 링크: https://leetcode.com/problems/triangle-judgement/submissions/1883771646/
2. 정답 코드:
select
x, y, z,
case when x >= y+z or y >= x+z or z >= x+y then 'No'
else 'Yes' end as triangle
from Triangle
- 문제 13
1. 문제 링크: https://leetcode.com/problems/fix-names-in-a-table/description/
2. 정답 코드:
select
user_id,
concat(upper(substring(name,1,1)), lower(substring(name,2))) as name
from Users
order by user_id
3. 오류 상황: 문자열 합치는 함수는 'concat'인데 파이썬에서 string 합치듯이 '+' 사용해서 오류 발생!
4. 시도 방법: GEMINI 질문... upper과 lower 함수는 구글링!
- substring 함수에서 마지막 인자 안적어주면 자동으로 '끝까지'
- 수업날 복습 (함수|모듈)
- 매개변수 vs 인자
- 매개변수(Parameter): 함수 정의할 떄 함수 내부로 전달받을 수 있는 변수
- 함수 선언부에 이름을 붙여놓은 것
- 인자(Argument): 함수를 호출할 떄 실제로 넘기는 값
- 호출 시 매개변수에 대응하는 실제 데이터를 인자로 전달
- 가변 인자(*args): 몇 개의 인자가 들어올지 모를 경우, args를 사용하면 인자를 튜플 형태로 받을 수 있음
def sum_all(*args):
total = 0
for num in args:
total += num
return total
print(sum_all(1, 2, 3)) # 6
print(sum_all(10, 20)) # 30
print(sum_all()) # 0
- 키워드 가변 인자 (**kwargs): 키워드 인자를 딕셔너리 형태로 받을 수 있음
def print_info(**kwargs):
for key, value in kwargs.items():
print(key, ":", value)
print_info(name="Eve", age=22, hobby="reading")
# name : Eve
# age : 22
# hobby : reading
- 람다 함수(Lambda Function): lambda 키워드를 사용하여 한 줄로 함수를 정의함
# 일반 함수
def add(a, b):
return a + b
# 람다 함수
add_lambda = lambda a, b: a + b
print(add(3, 5)) # 8
print(add_lambda(3, 5)) # 8
- Docstring (문서 문자열): """ (삼중 따옴표) 로 작성하는 것으로, 함수 사용법과 의도를 기록함
- 지역 변수 vs 전역 변수:
- 함수 안에서 선언된 변수는 지역 변수(local)
- 함수 밖에서 선언된 변수는 전역 변수(global)
x = 10 # 전역 변수
def my_func():
x = 5 # 지역 변수
print("함수 내부:", x)
my_func() # 함수 내부: 5
print("함수 외부:", x) # 함수 외부: 10
- 실습 문제 2: 단어 빈도 세기 함수
def word_count(sentence):
words = sentence.lower()
words = words.split()
cnt = {}
for w in words:
if w not in cnt:
cnt[w] = 1
else:
cnt[w] += 1
return cnt
print(word_count("Apple banana apple Orange orange banana apple"))
- if-else 문을 get 함수를 사용하여 한줄로 간단히 할 수 있음!!!
def word_count(sentence):
words = sentence.lower()
words = words.split()
cnt = {}
for w in words:
cnt[w] = cnt.get(w,0) + 1
return cnt
- random 모듈
- 무작위(랜덤) 값을 만들어 주는 파이썬 내장 모듈
- 게임, 추첨, 시뮬레이션, 테스트 데이터 만들 때 사용함
- random.randint(a,b) : a부터 b까지 정수 하나를 랜덤 반환
- random.randrange(a,b) : a부터 b-1까지 정수 하나를 랜덤 반환
- random.random() : 0 이상 1 미만의 실수 하나를 랜덤 반환
- random.choice(리스트) : 리스트 안에서 하나를 랜덤으로 뽑아줌
- random.shuffle(리스트) : 리스트의 순서를 랜덤으로 섞음
- random.sample(리스트, 개수) : 리스트에서 중복 없이 여러개를 뽑음
- 문풀날 심화문제
- 심화 문제 1 : 온라인 강의 수강생 관리 시스템
students = {
"민수": [80, 70, 90],
"영희": [40, 55, 60],
"지수": [100, 95, 90],
"철수": [30, 45, 20]
}
def average(scores):
try:
res = sum(scores) / len(scores)
return res
except ZeroDivisionError:
print("0으로 나눌 수 없습니다.")
def sixty(dctn):
newdict = {}
for student, score in dctn.items():
if score >= 60:
newdict[student] = score
return newdict
def highest(dctn):
maxscore = 0
maxstudent = ""
for student in dctn:
temp = dctn.get(student,0)
if maxscore < temp:
maxstudent = student
maxscore = temp
return maxstudent
def highest2(dctn):
return max(dctn, key=dctn.get)
avgdict = {student:round(average(students[student]),2) for student in students}
print(f"학생별 평균: {avgdict}")
score_sixty = sixty(avgdict)
print(f"합격자: {score_sixty}")
highest_student = highest(avgdict)
print(f"최고 평균 학생: {highest_student}")
- highest2 : for-loop / if문 사용 없이 max 함수로 한줄 작성 (key = dctn.get)
- 심화 문제 2 : 은행 계좌 시뮬레이터
# 문제 2
accounts = {
"A001": 50000,
"A002": 120000,
"A003": 30000
}
def deposit(accdict, acc, money):
if acc in accdict:
accdict[acc] += money
print(f"{acc} 잔액: {accdict.get(acc)}")
def withdrawal(accdict, acc, money):
if acc in accdict:
temp = accdict.get(acc,0)
if money > temp:
print(f"{acc} 출금 실패")
else:
accdict[acc] -= money
print(f"{acc} 잔액: {accdict.get(acc)}")
def whole(accdict):
return sum(accdict.values())
def danger(accdict):
dndict = [acc for acc, money in accdict.items() if money < 50000]
return dndict
deposit(accounts,"A001",20000)
withdrawal(accounts, "A003", 50000)
res = whole(accounts)
print(f"전체 은행 자산: {res}")
res = danger(accounts)
print(f"위험 계좌: {res}")
- whole : for-loop/if 문 사용 없이 sum() 함수와 dict.values() 함수 사용하여 한줄로 작성
- 심화 문제 3
# 문제 3
log = "error login success login error logout success login error"
from collections import defaultdict
def frequency(s):
s = s.lower()
words = s.split()
freqdict = defaultdict(int)
for w in words:
freqdict[w] += 1
return freqdict
def mostfreq(freqdict):
freq = 0
freqword = ""
for w, c in freqdict.items():
if c > freq:
freq = c
freqword = w
return freqword
def mostfreq2(freqdict):
return max(freqdict, key=freqdict.get)
def calculate_ratio(freqdict, word):
total = sum(freqdict.values())
if total == 0: return -1
freq = freqdict.get(word,0)
return round(freq / total * 100,2)
def twotimes(freqdict):
newdict = {w:c for w,c in freqdict.items() if c>=2}
return newdict
result = dict(frequency(log))
print(f"단어 빈도: {result}")
result1 = mostfreq(result)
print(f"최다 단어: {result1}")
result2 = calculate_ratio(result,result1)
if result2 == -1:
print("0으로 나눌 수 없습니다.")
else:
print(f"{result1} 비율: {result2}%")
result3 = twotimes(result)
print(f"중요 단어: {result3}")
- mostfreq2 : for-loop / if 문 사용 대신 max() 함수 사용하여 한줄로 작성 (key=freqdict.get)
- calculate_ratio : 경우를 try-except 대신 더 직관적으로 나눔 (if문)
- 즐거운 튜터링 시간~~~

튜터님 앞에서 장기자랑 하는 신인 걸그룹
ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ

튜터님께 질문 하다가 너무 솔직해져 버린 나
ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ ㅠㅠㅠ
이게 사실이라고요;;;ㅠ
'[데이터분석] 부트캠프 TIL' 카테고리의 다른 글
| 20260115 TIL (1) | 2026.01.15 |
|---|---|
| 20260114 TIL (1) | 2026.01.14 |
| 20260112 TIL (1) | 2026.01.12 |
| 20260111 TIL (1) | 2026.01.12 |
| 20260109 TIL (1) | 2026.01.09 |