En uno de los últimos proyectos que estamos desarrollando en Damavis, empezamos a crear un proceso de ETL desde cero. Por un lado, un miembro del equipo configuraba la arquitectura cloud y todos sus componentes. Mientras tanto, yo analizaba los datos y diseñaba la pipeline para su transformación. Ambos sabíamos que las transformaciones íbamos a realizarlas en una base de datos relacional (SQL) en la nube.
Sin embargo, este sistema aún no estaba configurado y los únicos datos disponibles eran ficheros de ejemplo. Mi objetivo era diseñar la pipeline en SQL, pero en un notebook de Jupyter por su gran interactividad y para analizar con Pandas. Y es justo aquí donde me encontré con DuckDB.
¿Qué es DuckDB?
DuckDB es una base de datos SQL orientada a columnas y diseñada para analítica. Entre sus características más importantes destacan su facilidad de instalación y uso, además de su amplio dialecto SQL. No obstante, su gran potencial se halla en su capacidad para leer datos de cualquier lugar, ya sean ficheros (Parquet, csv, etc.), otras bases de datos, plataformas cloud o, directamente, librerías como Pandas.
A continuación, exploraremos algunas características del cliente de Python de DuckDB. No obstante, la herramienta también tiene su propia interfaz de comandos (CLI) así como clientes en Java, R, etc.
Primeros pasos con DuckDB
En primer lugar, instalaremos el cliente de Python de DuckDB. Para ello, utilizaremos el comando pip:
pip install duckdbUna vez instalado, se puede ejecutar una sentencia SQL mediante la función .sql(). En el siguiente ejemplo se leen los datos de un fichero csv:
import duckdb
duckdb_data = duckdb.sql("SELECT * FROM read_csv('my_data.csv')")
duckdb_data
DuckDB también es capaz de leer de dataframes de Pandas, Polars y Arrow. Simplemente, se usa el nombre de la variable como si fuera una tabla. En el siguiente ejemplo, se crea un dataframe de Pandas y se realiza una query sobre él en DuckDB:
import pandas as pd
pandas_df = pd.DataFrame([['a', 'b'], ['c', 'd']],
columns=['col_1', 'col_2'])
duckdb.sql("SELECT * FROM pandas_df")
Si queremos que el resultado sea también un dataframe de Pandas, se puede usar el método .df() sobre el resultado de la query.
Cómo crear conexiones en DuckDB
Por defecto, DuckDB se conecta directamente a la memoria. De aquí es de donde puede leer dataframes como en el ejemplo anterior. No obstante, es posible crear un objeto de conexión directamente con la función .connect(). Para replicar la conexión a memoria se puede especificar la string :memory: tal y como se puede ver en este ejemplo:
con = duckdb.connect(':memory:')
con.sql("SELECT MAX(col_2) FROM pandas_df")
En caso de que queramos persistir las tablas creadas dentro de la base de datos, se puede especificar una ruta donde guardar un fichero de la base de datos DuckDB. En el siguiente ejemplo, se crea una conexión con el fichero db.duckdb y la tabla my_table:
import os
duckdb_con = duckdb.connect("db.duckdb")
os.listdir()
#############################
duckdb_con.sql("DROP TABLE IF EXISTS my_table")
duckdb_con.sql("""
CREATE TABLE my_table AS (
SELECT 1 x, 'example 1' y UNION ALL
SELECT 2 x, 'example 2' y UNION ALL
SELECT 3 x, 'example 3' y)
""")
duckdb_con.sql("SHOW TABLES")
#############################
duckdb_con.sql("SELECT * FROM my_table")
Conexiones de DuckDB a otras bases de datos
Por otra parte, es posible utilizar extensiones para realizar conexiones a otras bases de datos. Una de dichas extensiones permite la conexión con Postgres. Para llevar a cabo este proceso, hay que instalar la extensión correspondiente y después cargarla. A continuación, se puede incorporar la base de datos de Postgres a DuckDB con la sentencia ATTACH.
duckdb.install_extension('postgres')
duckdb.load_extension('postgres')
pg_uri = 'postgresql://my_user:my_pass@localhost:5432/my_db'
pg_con = duckdb.connect()
pg_con.sql(f"ATTACH '{pg_uri}' AS pg_db (TYPE POSTGRES)")
pg_con.sql("USE pg_db")
pg_con.sql("DROP TABLE IF EXISTS my_table")
pg_con.sql("""
CREATE TABLE my_table AS (
SELECT 4 x, 'example 4' y UNION ALL
SELECT 5 x, 'example 5' y UNION ALL
SELECT 6 x, 'example 6' y)
""")
pg_con.sql("SELECT * FROM my_table")
Para el ejemplo, se ha usado un contenedor de docker compose con Postgres con la siguiente configuración YAML:
name: my_postgres
services:
db:
image: postgres:latest
environment:
- POSTGRES_USER=my_user
- POSTGRES_PASSWORD=my_pass
- POSTGRES_DB=my_db
ports:
- "5432:5432"Funciones mágicas de SQL en DuckDB
En caso de estar trabajando en un entorno de notebooks Jupyter, es posible aumentar la “experiencia SQL” utilizando funciones mágicas de SQL combinadas con DuckDB. Para ello, primero es necesario instalar algunas dependencias adicionales:
pip install jupysql duckdb-engineUna vez instaladas las dependencias, se carga la función mágica de SQL:
%load_ext sql
# Optional:
%config SqlMagic.autopandas = True
%config SqlMagic.feedback = False
%config SqlMagic.displaycon = FalseLa sentencias de configuración son opcionales, pero muy recomendables. Sobre todo, la de autopandas, que hará que los resultados de las queries sean dataframes de Pandas y se puedan usar fácilmente con DuckDB.
La función mágica de SQL puede utilizarse de distintas formas. O bien en línea (%sql) mezclándola con código Python, o en bloque de código (%%sql), donde se puede beneficiar del coloreado automático de la sintaxis SQL. En los dos siguientes ejemplos se pueden ver ambos casos.
En el primero de ellos, se conecta a la base de datos de memoria y se lanza una sentencia SQL en línea:
%sql duckdb:///:memory:/
%sql SET python_scan_all_frames=True
new_df = %sql SELECT *, col_1 || col_2 AS col_3 FROM pandas_df
new_df
En el segundo ejemplo, se muestra cómo usar una conexión definida previamente (pg_con) para conectar con Postgres (en lugar de repetir la sentencia de ATTACH). En este caso, se usa un bloque de código SQL para hacer la query. Además, se muestra la sintaxis (opcional) para guardar el resultado en un dataframe (new_df << …).
%sql pg_con
#############################
%%sql new_df <<
SELECT *, 'ABC' AS z
FROM pg_db.my_table
#############################
new_df
Conclusión
DuckDB es una herramienta que permite usar un lenguaje tan común como el SQL de manera muy flexible y sencilla. Se puede usar como base de datos o para acompañar al usuario en sus análisis de datos. En nuestro caso, conseguimos desarrollar la pipeline de transformación de la ETL en SQL mientras que se montaba toda la arquitectura a su alrededor, incluida la propia base de datos.
Si este artículo te ha parecido interesante, te animamos a visitar la categoría Data Engineering para ver otros posts similares a este y a compartirlo en redes. ¡Hasta pronto!

