[리트코드]Medium|1193. Monthly Transactions I; CASE WHEN
https://leetcode.com/problems/monthly-transactions-i/description/
1. Problem
월별, 국가별로 전체 거래 건수/금액과 승인된(approved) 거래 건수/금액을 각각 산출해야 한다.
- 핵심 과제: 하나의 GROUP BY 안에서 전체 통계와 특정 조건을 만족하는 통계를 동시에 추출하는 효율적인 구조를 설계하는 것이다.
2. Solution: 집계 함수 내부에 논리 심기
CASE WHEN으로 조건에 맞는 값(1 또는 amount)만 골라낸 뒤, 그 결과물들을 한꺼번에 SUM으로 합산한다.
3. Takeaway: 집계 함수와 CASE WHEN의 올바른 위치 (객관적 분석)
- CASE WHEN의 위치가 왜 중요한가? (유진 님의 오답 분석):
- 오답 유형: CASE WHEN state = 'approved' THEN COUNT(amount) END
- 원인: SQL의 실행 순서상 GROUP BY가 일어난 후 CASE WHEN이 판단되는데, 이 구조는 "이미 그룹화된 덩어리에 대해 'state'가 무엇인지 묻는 것"과 같다. 하지만 한 그룹 안에는 approved와 declined가 섞여 있으므로 엔진은 판단을 내릴 수 없다.
- 정석: SUM(CASE WHEN ...) 처럼 개별 행 단위에서 먼저 조건을 판별하고, 그 결과값들을 마지막에 집계 함수가 수거하여 합치는 방식이 논리적으로 타당하다.
- 날짜 포맷팅의 디테일: DATE_FORMAT에서 % 기호의 위치(%Y-%m)를 정확히 지켜야 규격에 맞는 문자열이 생성된다.
- GROUP BY의 대원칙: 유진 님이 회고하신 것처럼, SELECT에 나열된 비집계 컬럼(month, country)은 반드시 GROUP BY에 포함되어야 데이터의 정합성이 유지된다.
Table: Transactions
+---------------+---------+
| Column Name | Type |
+---------------+---------+
| id | int |
| country | varchar |
| state | enum |
| amount | int |
| trans_date | date |
+---------------+---------+
id is the primary key of this table.
The table has information about incoming transactions.
The state column is an enum of type ["approved", "declined"].
Write an SQL query to find for each month and country, the number of transactions and their total amount, the number of approved transactions and their total amount.
Return the result table in any order.
The query result format is in the following example.
Example 1:
Input:
Transactions table:
+------+---------+----------+--------+------------+
| id | country | state | amount | trans_date |
+------+---------+----------+--------+------------+
| 121 | US | approved | 1000 | 2018-12-18 |
| 122 | US | declined | 2000 | 2018-12-19 |
| 123 | US | approved | 2000 | 2019-01-01 |
| 124 | DE | approved | 2000 | 2019-01-07 |
+------+---------+----------+--------+------------+
Output:
+----------+---------+-------------+----------------+--------------------+-----------------------+
| month | country | trans_count | approved_count | trans_total_amount | approved_total_amount |
+----------+---------+-------------+----------------+--------------------+-----------------------+
| 2018-12 | US | 2 | 1 | 3000 | 1000 |
| 2019-01 | US | 1 | 1 | 2000 | 2000 |
| 2019-01 | DE | 1 | 1 | 2000 | 2000 |
+----------+---------+-------------+----------------+--------------------+-----------------------+
1. 정답풀이
SELECT DATE_FORMAT(trans_date, '%Y-%m') as month, # 날짜 표기 형식
country,
COUNT(*) AS trans_count,
SUM(CASE WHEN state = 'approved' THEN 1 ELSE 0 END) AS approved_count, # 1/0으로 대체하여 집계
SUM(amount) AS trans_total_amount,
SUM(CASE WHEN state = 'approved' THEN amount ELSE 0 END) AS approved_total_amount #SUM으로 묶어주기. 승인된 거래 "금액 합"
FROM Transactions
GROUP BY month, country;
SELECT에 나오는 모든 컬럼은
- GROUP BY에 있거나
- 집계 함수 안에 있어야 한다
2. 나의 오답
SELECT DATE_FORMAT(trans_date, 'Y%-m%') as month,
country,
COUNT(trans_date) AS trans_count,
CASE WHEN state = 'approved' THEN COUNT(amount) END AS approved_count, # CASE WHEN COUNT()는 논리적으로 불가능
SUM(amount) AS trans_total_amount,
CASE WHEN state = 'approved' THEN COUNT(amount) END AS approved_total_amount
WHERE Transactions
GROUP BY month, country;