Posts
All the articles I've posted.
SELECT route,
CONCAT(ROUND(SUM(d_between_dist), 1), 'km') AS total_distance,
CONCAT(ROUND(AVG(d_between_dist), 2), 'km') AS average_distance
FROM subway_distance
GROUP BY route
ORDER BY ROUND(SUM(d_between_dist), 1) DESC;
-- SELECT route,
-- CONCAT(ROUND(SUM(d_between_dist), 1), 'km') AS total_distance,
-- CONCAT(ROUND(AVG(d_between_dist), 2), 'km') AS average_distance
-- FROM subway_distance
-- GROUP BY route
-- ORDER BY total_distance DESC;
문제에서 요구한 결과를 만들기 위해 쿼리에서 실제로 쓴 것들이다.
노선별 평균 역 사이 거리 조회하기
노선별로 SUM 과 AVG 를 각각 구해 ROUND 자릿수를 다르게 주고, CONCAT 으로 'km' 를 붙여 문자열로 만든다.
WITH cars_with_fee AS (
SELECT
c.car_id,
c.car_type,
FLOOR(c.daily_fee * 30 * (100 - p.discount_rate) / 100) AS fee
FROM
car_rental_company_car AS c
JOIN
car_rental_company_discount_plan AS p ON c.car_type = p.car_type
WHERE
c.car_type IN ('세단', 'SUV')
AND p.duration_type = '30일 이상'
)
SELECT
car_id,
car_type,
fee
FROM
cars_with_fee
WHERE
car_id NOT IN (
SELECT
car_id
FROM
car_rental_company_rental_history
WHERE
end_date >= '2022-11-01' AND start_date <= '2022-11-30'
)
AND fee >= 500000 AND fee < 2000000
ORDER BY
fee DESC,
car_type ASC,
car_id DESC;특정 기간동안 대여 가능한 자동차들의 대여비용 구하기
CTE 에서 30일 요금제 할인율을 FLOOR 로 적용해 두고, 해당 기간에 대여 기록이 겹치는 차를 NOT IN 으로 걸러 낸다.
SELECT pd.product_code, SUM(os.sales_amount) * pd.price as sales
FROM product as pd
JOIN
offline_sale as os
ON pd.product_id = os.product_id
GROUP BY pd.product_id
ORDER BY sales DESC, pd.product_code ASC
문제에서 요구한 결과를 만들기 위해 쿼리에서 실제로 쓴 것들이다.
- 테이블 1회 JOIN 으로 두 테이블을 연결
- GROUP BY 로 묶어서 집계
- ORDER BY 로 정렬 (내림차순 포함)
- 사용한 함수: SUM()
상품 별 오프라인 매출 구하기
상품과 오프라인 판매를 조인해 SUM(수량) × 단가로 매출을 만든다. GROUP BY 는 product_id 로 하고 정렬만 product_code 를 쓴다.
INF = float('inf')
n = int(input())
total_sum = 0
select_idx = []
for _ in range(n):
L = int(input())
jewels = list(map(int, input().split()))
cum_sum = [0] * (L + 1)
for i in range(1, L + 1):
cum_sum[i] += cum_sum[i - 1] + jewels[i - 1]
max_sum = -INF
max_start = 1
max_end = L
for k in range(L, 0, -1):
is_max = False
for i in range(0, L - k + 1):
part_sum = cum_sum[k + i] - cum_sum[i]
if max_sum > part_sum:
continue
# 최대값과 같고 이미 앞에서 그 값이 나온 경우
elif max_sum == part_sum and is_max:
continue
max_sum = part_sum
max_start = i + 1
max_end = k + i
is_max = True
total_sum += max_sum
select_idx.append((max_start, max_end))
print(total_sum)
for result in select_idx:
print(*result)보석 구매하기
백준 2313번 '보석 구매하기' (골드 5) 문제 풀이. dynamic programming, prefix sum, traceback 로 접근했다.
cur_num = 2
stack = [1]
result = ['+']
for _ in range(n):
target = int(input())
if not stack:
stack.append(cur_num)
result.append('+')
cur_num += 1
while stack and stack[-1] < target:
stack.append(cur_num)
result.append('+')
cur_num += 1
if stack and stack[-1] == target:
stack.pop()
result.append('-')
continue
if len(stack) == 0:
print(*result, sep='\n')
else:
print('NO')스택 수열
백준 1874번 '스택 수열' (실버 2) 문제 풀이. data structures, stack 로 접근했다.
N, M = map(int, input().split())
dxy = ((1, 2), (2, 1), (-1, 2), (2, -1), (1, -2), (-2, 1), (-1, -2), (-2, -1))
x, y = map(int, input().split())
enemy_list = [tuple(map(int, input().split())) for _ in range(M)]
result = [0] * M
q = deque([(x, y, 1)])
find_cnt = 0
visited = set([(x, y)])
while q:
cur_x, cur_y, t = q.popleft()
for dx, dy in dxy:
n_x, n_y = cur_x + dx, cur_y + dy
if (n_x, n_y) in visited:
continue
if (n_x, n_y) in enemy_list:
enemy_idx = enemy_list.index((n_x, n_y))
if result[enemy_idx] != 0:
continue
result[enemy_idx] = t
find_cnt += 1
if find_cnt == M:
break
q.append((n_x, n_y, t + 1))
visited.add((n_x, n_y))
else:
continue
break
print(*result)현명한 나이트
백준 18404번 '현명한 나이트' (실버 1) 문제 풀이. graph theory, graph traversal, bfs 로 접근했다.
-- 사번, 성명, 평가 등급, 성과금
-- 부서 정보
-- 사원 정보
-- 사원 평가 정보
WITH avg_emp AS (
SELECT he.emp_no, he.emp_name, he.sal,
CASE
WHEN AVG(hg.score) >= 96 THEN 'S'
WHEN AVG(hg.score) >= 90 THEN 'A'
WHEN AVG(hg.score) >= 80 THEN 'B'
ELSE 'C'
END AS grade
FROM hr_employees AS he
LEFT JOIN
hr_grade AS hg
ON he.emp_no = hg.emp_no
GROUP BY he.emp_no
)
SELECT emp_no, emp_name, grade,
CASE
WHEN grade = 'S' THEN sal * 0.2
WHEN grade = 'A' THEN sal * 0.15
WHEN grade = 'B' THEN sal * 0.1
WHEN grade = 'C' THEN 0
ELSE NULL
END AS bonus
FROM avg_emp
ORDER BY emp_no연간 평가점수에 해당하는 평가 등급 및 성과금 조회하기
CTE 에서 사원별 평균 점수를 CASE 로 S·A·B·C 등급으로 바꾸고, 바깥에서 등급별 지급률을 다시 CASE 로 적용해 성과금을 구한다.
WITH quarter AS (
SELECT
CASE
WHEN(QUARTER(differentiation_date)) = 1 THEN '1Q'
WHEN(QUARTER(differentiation_date)) = 2 THEN '2Q'
WHEN(QUARTER(differentiation_date)) = 3 THEN '3Q'
WHEN(QUARTER(differentiation_date)) = 4 THEN '4Q'
ELSE NULL
END AS quarter
FROM ecoli_data
)
SELECT quarter, COUNT(*) AS ecoli_count
FROM quarter
GROUP BY quarter
ORDER BY quarter
문제에서 요구한 결과를 만들기 위해 쿼리에서 실제로 쓴 것들이다.
분기별 분화된 대장균의 개체 수 구하기
QUARTER() 로 분화일을 분기 문자열로 바꾸는 CTE 를 만들고, 바깥에서 그 값으로 GROUP BY 해 분기별 개체 수를 센다.
from collections import Counter, defaultdict
input = sys.stdin.readline
print = sys.stdout.write
N = int(input())
students = [int(input()) for _ in range(N)]
MAX_STUDENT = max(students) + 1
counter = Counter(students)
toktok = defaultdict(int)
for i in range(1, MAX_STUDENT):
for j in range(i, MAX_STUDENT, i):
if j in counter:
toktok[j] += counter[i]
print("\n".join(str(toktok[s] - 1) for s in students) + "\n")머리 톡톡
백준 1241번 '머리 톡톡' (골드 5) 문제 풀이. math, number theory, primality test 로 접근했다.