날짜/시간 함수를 활용한 매출 분석
초급중급
학습 목표
이 레시피를 완료하면 다음을 할 수 있습니다:
- BigQuery의 날짜/시간 데이터 타입 (DATE, DATETIME, TIMESTAMP) 이해
- EXTRACT, DATE_TRUNC 함수로 시간 단위 추출
- DATE_ADD/SUB로 기간 비교 분석
- DATE_DIFF로 기간 계산 및 KPI 도출
BigQuery 실행 환경 설정
from google.cloud import bigquery
import pandas as pd
# 인증 설정 (서비스 계정 키 사용 시)
# import os
# os.environ["GOOGLE_APPLICATION_CREDENTIALS"] = "path/to/your-key.json"
# BigQuery 클라이언트 생성
client = bigquery.Client(project='your-project-id')
# 쿼리 실행 함수
def run_query(query):
return client.query(query).to_dataframe()ℹ️
프로젝트 ID 설정
위 코드에서 your-project-id를 본인의 GCP 프로젝트 ID로 변경하세요.
1. DATE vs DATETIME vs TIMESTAMP
이론
BigQuery는 세 가지 주요 시간 데이터 타입을 제공합니다:
| 타입 | 형식 | 예시 | 특징 |
|---|---|---|---|
| DATE | YYYY-MM-DD | 2024-01-15 | 날짜만 저장, 시간 정보 없음 |
| DATETIME | YYYY-MM-DD HH:MM:SS | 2024-01-15 14:30:00 | 날짜 + 시간, 타임존 없음 |
| TIMESTAMP | YYYY-MM-DD HH:MM:SS UTC | 2024-01-15 14:30:00+00:00 | 날짜 + 시간 + 타임존 (UTC 기준) |
ℹ️
언제 어떤 타입을 사용할까?
- DATE: 생년월일, 가입일 등 시간이 중요하지 않은 경우
- DATETIME: 로컬 시간 기준 이벤트 (예약 시간, 영업 시간)
- TIMESTAMP: 전 세계에서 발생하는 이벤트의 정확한 시점 기록 (주문 시간, 로그)
주요 함수
-- 현재 날짜/시간 조회
CURRENT_DATE() -- 현재 날짜
CURRENT_DATETIME() -- 현재 날짜시간
CURRENT_TIMESTAMP() -- 현재 타임스탬프
-- 타입 변환
CAST(timestamp_col AS DATE) -- TIMESTAMP → DATE
CAST(timestamp_col AS DATETIME) -- TIMESTAMP → DATETIME실습: 날짜 타입 비교
SELECT
CURRENT_DATE() AS current_date,
CURRENT_DATETIME() AS current_datetime,
CURRENT_TIMESTAMP() AS current_timestamp,
-- created_at을 각 타입으로 변환
CAST(created_at AS DATE) AS order_date,
CAST(created_at AS DATETIME) AS order_datetime,
created_at AS order_timestamp
FROM `your-project-id.thelook_ecommerce.orders`
LIMIT 5실행 결과
| current_date | current_datetime | current_timestamp | order_date | order_datetime | order_timestamp |
|---|---|---|---|---|---|
| 2024-11-19 | 2024-11-19 10:26:43 | 2024-11-19 10:26:43+00:00 | 2023-10-11 | 2023-10-11 15:31:00 | 2023-10-11 15:31:00+00:00 |
2. EXTRACT 함수 - 연/월/일/요일 추출
이론
EXTRACT 함수는 날짜/시간에서 특정 부분만 추출합니다.
EXTRACT(part FROM date_expression)| Part | 설명 | 반환값 범위 |
|---|---|---|
| YEAR | 연도 | 예: 2024 |
| MONTH | 월 | 1-12 |
| DAY | 일 | 1-31 |
| DAYOFWEEK | 요일 | 1(일)~7(토) |
| DAYOFYEAR | 연중 일수 | 1-366 |
| WEEK | 주차 | 0-53 |
| QUARTER | 분기 | 1-4 |
| HOUR | 시간 | 0-23 |
| MINUTE | 분 | 0-59 |
⚠️
요일 주의사항
BigQuery의 DAYOFWEEK는 일요일이 1, 토요일이 7입니다.
실습: 요일별 주문 분석
SELECT
EXTRACT(DAYOFWEEK FROM created_at) AS day_of_week,
CASE EXTRACT(DAYOFWEEK FROM created_at)
WHEN 1 THEN '일요일'
WHEN 2 THEN '월요일'
WHEN 3 THEN '화요일'
WHEN 4 THEN '수요일'
WHEN 5 THEN '목요일'
WHEN 6 THEN '금요일'
WHEN 7 THEN '토요일'
END AS day_name,
COUNT(*) AS order_count
FROM `your-project-id.thelook_ecommerce.orders`
GROUP BY day_of_week, day_name
ORDER BY day_of_week실행 결과
| day_of_week | day_name | order_count |
|---|---|---|
| 1 | 일요일 | 18,384 |
| 2 | 월요일 | 17,916 |
| 3 | 화요일 | 17,617 |
| 4 | 수요일 | 17,313 |
| 5 | 목요일 | 17,526 |
| 6 | 금요일 | 17,725 |
| 7 | 토요일 | 18,312 |
💡
인사이트
주말(토/일)의 주문이 평일보다 약간 많습니다. 이커머스에서는 흔한 패턴으로, 주말 프로모션 전략 수립에 활용할 수 있습니다.
3. DATE_TRUNC - 기간 단위 집계
이론
DATE_TRUNC는 날짜를 특정 단위로 잘라냅니다. 월별, 주별, 분기별 집계에 유용합니다.
DATE_TRUNC(date_expression, date_part)| date_part | 입력 | 결과 |
|---|---|---|
| DAY | 2024-03-15 14:30:00 | 2024-03-15 |
| WEEK | 2024-03-15 14:30:00 | 2024-03-11 (월요일) |
| MONTH | 2024-03-15 14:30:00 | 2024-03-01 |
| QUARTER | 2024-03-15 14:30:00 | 2024-01-01 |
| YEAR | 2024-03-15 14:30:00 | 2024-01-01 |
실습: 월별 매출 트렌드
SELECT
DATE_TRUNC(CAST(o.created_at AS DATE), MONTH) AS month,
COUNT(DISTINCT o.order_id) AS order_count,
COUNT(DISTINCT o.user_id) AS customer_count,
SUM(oi.sale_price) AS total_revenue,
ROUND(SUM(oi.sale_price) / COUNT(DISTINCT o.order_id), 2) AS avg_order_value
FROM `your-project-id.thelook_ecommerce.orders` o
JOIN `your-project-id.thelook_ecommerce.order_items` oi ON o.order_id = oi.order_id
WHERE o.created_at >= '2024-01-01'
GROUP BY month
ORDER BY month실행 결과
| month | order_count | customer_count | total_revenue | avg_order_value |
|---|---|---|---|---|
| 2024-01-01 | 1,983 | 1,892 | 156,234.50 | 78.78 |
| 2024-02-01 | 1,928 | 1,845 | 148,923.75 | 77.24 |
| 2024-03-01 | 2,209 | 2,098 | 172,456.30 | 78.07 |
| … | … | … | … | … |
4. DATE_DIFF - 기간 계산
이론
DATE_DIFF는 두 날짜 사이의 차이를 계산합니다.
DATE_DIFF(end_date, start_date, date_part)| 계산 | SQL | 결과 |
|---|---|---|
| 일수 차이 | DATE_DIFF('2024-03-15', '2024-03-10', DAY) | 5 |
| 월수 차이 | DATE_DIFF('2024-06-01', '2024-03-01', MONTH) | 3 |
| 연수 차이 | DATE_DIFF('2025-01-01', '2024-01-01', YEAR) | 1 |
실습: 고객 활동 기간 분석
SELECT
user_id,
MIN(CAST(created_at AS DATE)) AS first_order_date,
MAX(CAST(created_at AS DATE)) AS last_order_date,
DATE_DIFF(MAX(CAST(created_at AS DATE)), MIN(CAST(created_at AS DATE)), DAY) AS days_active,
COUNT(DISTINCT order_id) AS total_orders,
ROUND(
COUNT(DISTINCT order_id) * 1.0 /
NULLIF(DATE_DIFF(MAX(CAST(created_at AS DATE)), MIN(CAST(created_at AS DATE)), MONTH), 0),
2
) AS orders_per_month
FROM `your-project-id.thelook_ecommerce.orders`
GROUP BY user_id
HAVING COUNT(DISTINCT order_id) > 1 -- 2회 이상 주문 고객만
ORDER BY days_active DESC
LIMIT 10실행 결과
| user_id | first_order_date | last_order_date | days_active | total_orders | orders_per_month |
|---|---|---|---|---|---|
| 4523 | 2023-01-02 | 2024-11-15 | 682 | 8 | 0.35 |
| 7891 | 2023-01-05 | 2024-10-28 | 662 | 5 | 0.23 |
| 2345 | 2023-01-08 | 2024-10-20 | 651 | 6 | 0.28 |
| … | … | … | … | … | … |
5. 전월/전년 대비 분석
이론
시계열 분석에서 가장 중요한 것은 기간 대비 비교입니다. 전월 대비(MoM), 전년 대비(YoY) 성장률을 계산하는 방법을 알아봅니다.
-- 전월 데이터 조인
DATE_SUB(current_month, INTERVAL 1 MONTH)
-- 전년 동월 데이터 조인
DATE_SUB(current_month, INTERVAL 1 YEAR)실습: 전월 대비 매출 성장률
WITH monthly_revenue AS (
SELECT
DATE_TRUNC(CAST(o.created_at AS DATE), MONTH) AS month,
SUM(oi.sale_price) AS revenue
FROM `your-project-id.thelook_ecommerce.orders` o
JOIN `your-project-id.thelook_ecommerce.order_items` oi ON o.order_id = oi.order_id
GROUP BY month
)
SELECT
curr.month,
curr.revenue AS current_revenue,
prev.revenue AS previous_revenue,
ROUND((curr.revenue - prev.revenue) / prev.revenue * 100, 2) AS mom_growth_pct
FROM monthly_revenue curr
LEFT JOIN monthly_revenue prev
ON curr.month = DATE_ADD(prev.month, INTERVAL 1 MONTH)
WHERE curr.month >= '2024-01-01'
ORDER BY curr.month실행 결과
| month | current_revenue | previous_revenue | mom_growth_pct |
|---|---|---|---|
| 2024-01-01 | 156,234.50 | 142,567.80 | 9.58 |
| 2024-02-01 | 148,923.75 | 156,234.50 | -4.68 |
| 2024-03-01 | 172,456.30 | 148,923.75 | 15.80 |
💡
실무 활용
- MoM (Month over Month): 단기 트렌드 파악, 계절성 영향 큼
- YoY (Year over Year): 계절성 제거, 중장기 성장 추세 파악
- QoQ (Quarter over Quarter): 분기별 사업 목표 달성도 측정
퀴즈
문제 1: 시간대별 주문 분석
orders 테이블에서:
- 주문 시간(시)을 추출하여 시간대별 주문 건수를 집계하세요
- 어떤 시간대에 주문이 가장 많은지 파악하세요
정답 보기
SELECT
EXTRACT(HOUR FROM created_at) AS hour,
COUNT(*) AS order_count,
ROUND(COUNT(*) * 100.0 / SUM(COUNT(*)) OVER(), 2) AS pct
FROM `your-project-id.thelook_ecommerce.orders`
GROUP BY hour
ORDER BY hour해설:
EXTRACT(HOUR FROM created_at)로 시간을 추출합니다- 윈도우 함수
SUM(...) OVER()로 전체 대비 비율을 계산합니다 - 일반적으로 오후 2-4시, 저녁 8-10시에 주문이 집중됩니다
문제 2: 주문 후 배송까지 소요 기간
order_items 테이블에서:
- 배송 완료된 주문의 평균 배송 소요일을 계산하세요
- 월별로 배송 소요일 추이를 분석하세요
정답 보기
SELECT
DATE_TRUNC(CAST(shipped_at AS DATE), MONTH) AS month,
COUNT(*) AS delivered_count,
ROUND(AVG(DATE_DIFF(CAST(delivered_at AS DATE), CAST(shipped_at AS DATE), DAY)), 2) AS avg_delivery_days
FROM `your-project-id.thelook_ecommerce.order_items`
WHERE delivered_at IS NOT NULL
GROUP BY month
ORDER BY month해설:
DATE_DIFF로 배송 시작일과 완료일의 차이를 계산합니다AVG로 평균을 구합니다- NULL 체크로 실제 배송 완료된 건만 필터링합니다
정리
| 함수 | 용도 | 예시 |
|---|---|---|
EXTRACT | 날짜에서 특정 부분 추출 | 요일별, 시간대별 분석 |
DATE_TRUNC | 날짜를 특정 단위로 절삭 | 월별, 분기별 집계 |
DATE_DIFF | 두 날짜 간 차이 계산 | 리텐션, 배송 소요일 |
DATE_ADD/SUB | 날짜 더하기/빼기 | 전월/전년 대비 분석 |
다음 단계
날짜/시간 함수를 마스터했습니다! 다음으로 그룹화와 집계에서 더 복잡한 집계 분석을 배워보세요.
Last updated on