https://product.kyobobook.co.kr/detail/S000220221456
LUVIT EPL과 유튜브 데이터로 배우는 DuckDB | 이기준 - 교보문고
LUVIT EPL과 유튜브 데이터로 배우는 DuckDB | 복잡한 데이터 분석 흐름을 더 단순하게 만드는 DuckDB 최근 주목받고 있는 DuckDB를 활용해 SQL 기반 데이터 분석과 실전 프로젝트를 학습할 수 있도록 구
product.kyobobook.co.kr
앞선 "DuckDB + Python: SQL로 CSV 파일 조회하기"라는 글에서 DuckDB를 사용해 데이터를 데이터베이스에 적재하지 않고도 CSV 파일을 직접 SQL로 조회하는 방법을 살펴보았습니다. 아직 Part 1을 읽지 못했다면 먼저 확인해 보시기 바랍니다.
이번 Part 2에서는 한 단계 더 나아가 다음 내용을 배워보겠습니다.
- 여러 CSV 파일을 함께 조회하기
- 고객(Customer) 데이터와 주문(Order) 데이터 조인하기
- 주문 수가 가장 많은 상위 5명의 고객 찾기
- CSV 파일을 Parquet 파일로 변환하기
- Parquet 파일 조회하기
- 여러 Parquet 파일 조인하기
- 쿼리 결과를 Pandas DataFrame으로 변환하기
- LIMIT와 OFFSET을 활용한 페이지네이션 구현하기
그럼 시작해 보겠습니다.
이번 글에서는 customers.csv와 orders.csv 두 개의 데이터셋을 사용합니다.
두 개의 CSV 파일 조인하기
일반적으로는 두 데이터셋을 Pandas로 읽어온 뒤 merge()를 사용해 결합합니다. 하지만 DuckDB에서는 파일을 직접 조회할 수 있습니다.
import duckdb
query = """
SELECT
c.customer_id,
c.name,
c.city,
o.order_id,
o.amount
FROM 'customers.csv' c
JOIN 'orders.csv' o
ON c.customer_id = o.customer_id
"""
result = duckdb.sql(query)
print(result.df())
출력 결과:

주문 수가 가장 많은 상위 5명의 고객 찾기
가장 활발하게 구매하는 고객이 누구인지 확인하고 싶다면 다음과 같이 조회할 수 있습니다.
query = """
SELECT
c.customer_id,
c.name,
c.city,
COUNT(o.order_id) AS total_orders
FROM 'customers.csv' c
JOIN 'orders.csv' o
ON c.customer_id = o.customer_id
GROUP BY
c.customer_id,
c.name,
c.city
ORDER BY total_orders DESC
LIMIT 5
"""
top_customers = duckdb.sql(query)
print(top_customers.df())
출력 결과:

CSV 파일을 Parquet 파일로 변환하기
Parquet은 대용량 데이터셋에 대한 빠르고 효율적인 분석 쿼리를 위해 설계된 컬럼형 저장 포맷입니다. Parquet 파일은 분석 작업에 매우 최적화되어 있습니다.
주문 데이터셋을 변환해 보겠습니다.
import pandas as pd
# CSV 읽기
orders_df = pd.read_csv("orders.csv")
# Parquet로 저장
orders_df.to_parquet("orders.parquet", index=False)
print("orders.parquet created successfully!")
고객 데이터셋도 동일하게 변환할 수 있습니다.
import pandas as pd
# CSV 읽기
customers_df = pd.read_csv("customers.csv")
# Parquet로 저장
customers_df.to_parquet("customers.parquet", index=False)
print("customers.parquet created successfully!")
Parquet 파일 조회하기
DuckDB는 Parquet 파일도 직접 조회할 수 있습니다.
query = """
SELECT *
FROM read_parquet('orders.parquet')
"""
result = duckdb.sql(query)
print(result.df())
출력 결과:

두 개의 Parquet 파일 조인하기
이제 customers.parquet과 orders.parquet 파일을 CSV와 동일한 방식으로 조인할 수 있습니다.
query = """
SELECT
c.customer_id,
c.name,
COUNT(o.order_id) AS total_orders
FROM 'customers.parquet' c
JOIN 'orders.parquet' o
ON c.customer_id = o.customer_id
GROUP BY
c.customer_id,
c.name
ORDER BY total_orders DESC
LIMIT 5
"""
result = duckdb.sql(query)
print(result.df())
COUNT() → 집계 함수입니다.
GROUP BY → 동일한 고객 데이터를 하나의 그룹으로 묶습니다.
ORDER BY → 결과를 정렬합니다.
출력 결과:

CSV 파일과 Parquet 파일 함께 조인하기
DuckDB의 정말 멋진 점 중 하나는 파일 형식이 서로 달라도 된다는 것입니다.
다음과 같은 쿼리가 가능합니다.
query = """
SELECT
c.name,
COUNT(o.order_id) AS total_orders
FROM 'customers.csv' c
JOIN 'orders.parquet' o
ON c.customer_id = o.customer_id
GROUP BY c.name
ORDER BY total_orders DESC
"""
result = duckdb.sql(query)
print(result.df())
출력 결과:

DuckDB가 내부적으로 모든 처리를 수행해 주므로 사용자는 파일 형식 차이를 신경 쓸 필요가 없습니다.
결과를 Pandas로 내보내기
top_customers_df = duckdb.sql(query).df()
print(top_customers_df.head())
출력 결과:

DuckDB에서는 파일 자체가 데이터베이스가 됩니다. CSV 파일을 조회하고, Parquet 파일을 조회하며, 여러 데이터셋을 조인하고, CSV와 Parquet을 함께 사용할 수 있으며, 결과를 Pandas로 쉽게 변환할 수 있습니다.
이제 한 단계 더 나아가 DuckDB에서 페이지네이션을 구현해 보겠습니다.
LIMIT와 OFFSET을 이용한 페이지네이션
데이터를 한 번만 분석하는 것이 아니라 API나 대시보드를 구축한다고 가정해 보겠습니다.
이 경우 모든 결과를 한 번에 가져오기보다는 페이지 단위로 조회하는 것이 좋습니다.
페이지 1 (처음 5개 행)
query = """
SELECT *
FROM 'orders.parquet'
ORDER BY order_id
LIMIT 5 OFFSET 0
"""
print(duckdb.sql(query).df())
출력 결과:

페이지 2 (다음 5개 행)
query = """
SELECT *
FROM 'orders.parquet'
ORDER BY order_id
LIMIT 5 OFFSET 5
"""
print(duckdb.sql(query).df())
출력 결과:

LIMIT은 가져올 행 수를 의미하며, OFFSET은 건너뛸 행 수를 의미합니다.
모든 기능 결합하기 (JOIN + AGG + LIMIT)
이제 주문 수 기준 상위 5명의 고객을 조회해 보겠습니다.
query = """
SELECT
c.customer_id,
c.name,
c.city,
COUNT(o.order_id) AS total_orders
FROM 'customers.csv' c
JOIN 'orders.parquet' o
ON c.customer_id = o.customer_id
GROUP BY
c.customer_id,
c.name,
c.city
ORDER BY total_orders DESC
LIMIT 5
"""
print(duckdb.sql(query).df())
출력 결과:

집계 전에 필터링하기
그룹화 전에 조건을 적용하는 것도 가능합니다.
예를 들어 Lagos 지역 고객만 대상으로 상위 고객을 조회할 수 있습니다.
query = """
SELECT
c.name,
COUNT(o.order_id) AS total_orders
FROM 'customers.csv' c
JOIN 'orders.parquet' o
ON c.customer_id = o.customer_id
WHERE c.city = 'Lagos'
GROUP BY c.name
ORDER BY total_orders DESC
"""
print(duckdb.sql(query).df())
출력 결과:

결론
Part 1에서는 SQL을 사용하여 CSV 파일을 조회하는 방법을 배웠습니다. 이번 글에서는 여러 CSV 파일 조인, CSV 및 Parquet 파일 조회, 데이터 집계, 정렬 및 순위 계산, 페이지네이션 구현까지 살펴보았습니다. 이 모든 작업을 PostgreSQL이나 별도의 서버를 구축하지 않고 수행할 수 있습니다.
이 시점부터 DuckDB는 단순한 라이브러리라기보다 Python 애플리케이션 내부에서 동작하는 경량 분석 데이터베이스처럼 느껴지기 시작합니다.
'EPL과 유튜브 데이터로 배우는 DuckDB' 카테고리의 다른 글
| DuckDB: 2026년 데이터 분석가를 위한 가장 과소 평가된 도구 (0) | 2026.06.21 |
|---|---|
| DuckDB + Python: SQL로 CSV 파일 다루기 part 1 (0) | 2026.06.20 |
| SQL Window Function에서 ROWS와 RANGE (0) | 2026.06.19 |
| 24~25 EPL 팀 중 홈에서 강한 팀 (0) | 2026.06.17 |
| 리버풀과 토트넘의 포지션별 공격 결과 (0) | 2026.06.17 |
댓글