lección 2
Tu entorno de práctica: DuckDB en local y en la nube
Instala DuckDB en tu portátil con pip, carga CSVs automáticamente, crea tu propia base de datos y entiende cuándo usar DuckDB vs PostgreSQL.
⏱ 50 min
En la lección anterior ejecutaste SQL directamente en el navegador. Eso es perfecto para aprender y practicar, pero en tu trabajo real necesitarás un entorno local: explorar tus propios CSVs, conectar con bases de datos, automatizar con Python. En esta lección vas a instalar DuckDB en tu portátil — un pip install y listo — y vas a descubrir por qué es la herramienta favorita de los ingenieros de datos para prototipar y explorar.
La analogía perfecta: la plataforma web es el simulador de vuelo (practicas sin riesgo). DuckDB en local es tu avioneta real (vuelas con datos de verdad, sin las restricciones del navegador). Y PostgreSQL — que verás más adelante con Docker — es el avión comercial de producción (múltiples pilotos, pasajeros, torre de control).
### Instalar DuckDB: un pip install y nada más
DuckDB se instala como cualquier librería de Python. Asegúrate de tener tu entorno virtual activado (lo creamos en la Skill 3) y ejecuta:
1# 🟦 Windows (PowerShell)2.\venv\Scripts\Activate.ps13pip install duckdb4python -c "import duckdb; print(f'DuckDB {duckdb.__version__} instalado correctamente')"
Instalación en Windows
1# 🍎 Mac (Terminal/zsh)2source venv/bin/activate3pip install duckdb4python -c "import duckdb; print(f'DuckDB {duckdb.__version__} instalado correctamente')"
Instalación en Mac
Eso es todo. No hay servidor que levantar, no hay puerto que configurar, no hay usuario que crear. DuckDB vive dentro de tu proceso de Python. Cuando tu script termina, DuckDB se cierra limpiamente. Es la definición de "zero config".
Si no has creado un entorno virtual todavía, hazlo ahora: python -m venv venv y luego actívalo. Nunca instales librerías en el Python global del sistema — es una receta para el desastre.
### DuckDB en Python: conexión y queries
Hay dos modos de conexión: en memoria (los datos desaparecen al cerrar) y persistente (se guardan en un archivo .duckdb). Para explorar y prototipar, usa memoria. Para proyectos reales, usa un archivo:
1import duckdb23# Modo 1: En memoria (datos temporales)4con = duckdb.connect()5result = con.sql("SELECT 42 AS respuesta, CURRENT_DATE AS hoy")6print(result)78# Modo 2: Persistente (se guarda en disco)9con = duckdb.connect('mi_proyecto.duckdb')10con.sql("CREATE TABLE IF NOT EXISTS test (id INTEGER, nombre VARCHAR)")11con.sql("INSERT INTO test VALUES (1, 'Hola DuckDB')")12print(con.sql("SELECT * FROM test"))
Dos modos: en memoria (exploración) y persistente (proyectos)
### generate_series: crear datos de prueba al vuelo
Una de las funciones más útiles de DuckDB es generate_series. Genera secuencias de números que puedes usar para crear tablas de prueba sin necesitar un CSV. Es como un generador de datos bajo demanda:
1import duckdb23con = duckdb.connect()45# Generar 10 clientes ficticios6result = con.sql("""7 SELECT8 i AS id,9 'Cliente_' || i AS nombre,10 ['Madrid','Barcelona','Valencia','Sevilla','Bilbao'][1 + (i % 5)] AS ciudad,11 (random() * 1000)::INTEGER AS gasto_total12 FROM generate_series(1, 10) AS t(i)13""")14print(result)
generate_series + expresiones = datos de prueba instantáneos
### Cargar CSVs: donde DuckDB es mágico
En PostgreSQL, cargar un CSV requiere CREATE TABLE con tipos explícitos, COPY FROM, gestionar errores de encoding... En DuckDB, una línea. La función read_csv_auto detecta separadores, tipos de datos, cabeceras y encoding automáticamente:
1import duckdb23con = duckdb.connect()45# Cargar un CSV en una tabla (DuckDB infiere TODO)6con.sql("""7 CREATE TABLE ventas AS8 SELECT * FROM read_csv_auto('datos/ventas_2024.csv')9""")1011# ¿Qué tipos detectó?12con.sql("DESCRIBE ventas").show()1314# Primera query analítica15con.sql("""16 SELECT17 region,18 COUNT(*) AS num_ventas,19 SUM(importe)::INTEGER AS total,20 ROUND(AVG(importe), 2) AS ticket_medio21 FROM ventas22 GROUP BY region23 ORDER BY total DESC24""").show()
read_csv_auto: carga CSVs sin definir esquema — DuckDB lo infiere solo
DuckDB también puede leer Parquet (read_parquet), JSON (read_json) y archivos remotos por HTTP. Incluso puedes hacer SELECT * FROM read_csv_auto("https://...url.../datos.csv"). Esto lo exploraremos a fondo en la Skill 12 (Data Lakes).
### Crear tu propia base de datos: ecommerce.duckdb
Vamos a crear una base de datos persistente con datos de un e-commerce. La usarás para practicar fuera de la plataforma web:
1import duckdb23con = duckdb.connect('ecommerce.duckdb')45# Categorías6con.sql("""7 CREATE OR REPLACE TABLE categorias AS8 SELECT * FROM (VALUES9 (1, 'Electrónica', 'Dispositivos y gadgets'),10 (2, 'Hogar', 'Muebles y decoración'),11 (3, 'Ropa', 'Moda y accesorios'),12 (4, 'Deportes', 'Equipamiento deportivo'),13 (5, 'Libros', 'Libros y material educativo')14 ) AS t(id, nombre, descripcion)15""")1617# Productos (200 productos con categoria_id)18con.sql("""19 CREATE OR REPLACE TABLE productos AS20 SELECT21 i AS id,22 'Producto_' || i AS nombre,23 ['Electrónica','Hogar','Ropa','Deportes','Libros'][1 + (i % 5)] AS categoria,24 1 + (i % 5) AS categoria_id,25 ROUND(5 + (i * 37) % 200 + ((i * 13) % 100) / 100.0, 2) AS precio,26 10 + (i * 73) % 490 AS stock27 FROM generate_series(1, 200) AS t(i)28""")2930# Clientes (1000)31con.sql("""32 CREATE OR REPLACE TABLE clientes AS33 SELECT34 i AS id,35 'Cliente_' || i AS nombre,36 'cliente' || i || '@email.com' AS email,37 ['Madrid','Barcelona','Valencia','Sevilla','Bilbao'][1 + (i % 5)] AS ciudad,38 DATE '2020-01-01' + INTERVAL (i * 3) DAY AS fecha_registro,39 ['email','google','facebook','organico','referido'][1 + (i % 5)] AS canal_adquisicion,40 (i % 7 = 0) AS es_vip41 FROM generate_series(1, 1000) AS t(i)42""")4344# Pedidos (5000 con producto_id)45con.sql("""46 CREATE OR REPLACE TABLE pedidos AS47 SELECT48 i AS id,49 1 + (i % 1000) AS cliente_id,50 1 + (i % 200) AS producto_id,51 1 + (i % 5) AS cantidad,52 DATE '2023-01-01' + INTERVAL (i % 730) DAY AS fecha,53 ROUND(10 + (i * 37) % 491 + ((i * 13) % 100) / 100.0, 2) AS importe,54 CASE WHEN i % 10 < 7 THEN 'completado'55 WHEN i % 10 < 9 THEN 'cancelado'56 ELSE 'devuelto' END AS estado57 FROM generate_series(1, 5000) AS t(i)58""")5960# Líneas de pedido (detalle de cada pedido)61con.sql("""62 CREATE OR REPLACE TABLE lineas_pedido AS63 SELECT64 i AS id,65 1 + (i % 5000) AS pedido_id,66 1 + (i % 200) AS producto_id,67 1 + (i % 4) AS cantidad,68 ROUND(5 + (i * 41) % 200 + ((i * 17) % 100) / 100.0, 2) AS precio_unitario69 FROM generate_series(1, 10000) AS t(i)70""")7172print('Base de datos creada: ecommerce.duckdb')73for tabla in ['categorias', 'productos', 'clientes', 'pedidos', 'lineas_pedido']:74 n = con.sql(f'SELECT COUNT(*) FROM {tabla}').fetchone()[0]75 print(f" {tabla}: {n} filas")
Script completo: crea todas las tablas que usarás en las lecciones L3-L11
### DuckDB vs PostgreSQL: no son rivales, son compañeros
Un error común es pensar que DuckDB reemplaza a PostgreSQL. No. Son herramientas complementarias con propósitos distintos. PostgreSQL es tu base de datos de producción: gestiona transacciones, usuarios concurrentes, integridad referencial. Es donde tu aplicación web guarda los pedidos en tiempo real. DuckDB es tu laboratorio personal: exploras datos, pruebas queries, generas reportes, analizas CSVs.
La analogía: PostgreSQL es la cocina del restaurante (producción, volumen, múltiples cocineros, pedidos en tiempo real, normas de seguridad alimentaria). DuckDB es tu cocina en casa (experimentas, pruebas recetas nuevas, analizas ingredientes, sin presión de servicio). Ambas son cocinas, pero con propósitos completamente diferentes.
- PostgreSQL: miles de usuarios simultáneos, inserciones en tiempo real, ACID completo, permisos por usuario. Necesita servidor (Docker).
- DuckDB: un solo usuario (tú), lecturas masivas, sin servidor, cabe en un pip install. Ideal para analítica y exploración.
- En tu carrera usarás AMBOS: PostgreSQL para los datos de producción, DuckDB para analizarlos sin tocar producción.
- La sintaxis SQL es 95% idéntica. Lo que aprendes en uno funciona en el otro.
No uses DuckDB como base de datos de una aplicación web. No está diseñado para múltiples escritores concurrentes. Para eso existe PostgreSQL (que verás en la Skill 6 de Docker). DuckDB es tu herramienta de análisis, no tu base de producción.
### Verificación final: un JOIN en tu base local
1import duckdb23con = duckdb.connect('ecommerce.duckdb')45# Si ves resultados, tu entorno local funciona perfectamente6con.sql("""7 SELECT8 c.ciudad,9 COUNT(DISTINCT c.id) AS clientes,10 COUNT(p.id) AS pedidos,11 SUM(p.importe)::INTEGER AS gasto_total,12 ROUND(AVG(p.importe), 2) AS ticket_medio13 FROM clientes c14 LEFT JOIN pedidos p ON p.cliente_id = c.id15 WHERE p.estado = 'completado'16 GROUP BY c.ciudad17 ORDER BY gasto_total DESC18""").show()
Si ves una tabla con 5 ciudades y sus métricas, todo funciona correctamente.
Ya tienes dos entornos de práctica: la plataforma web (inmediata, sin instalar nada) y DuckDB en tu portátil (para tus propios datos, automatización con Python y trabajo profesional). A partir de la próxima lección, todos los ejercicios SQL se ejecutan directamente aquí en el navegador. Si quieres practicar más, replica los ejercicios en tu DuckDB local.
## ejercicios
Instalar DuckDB y verificar la versión
Instala DuckDB con pip y verifica que funciona. Importa la librería, imprime la versión, crea una conexión en memoria y ejecuta una query que devuelva tu nombre y la fecha actual.
Generar datos con generate_series
El equipo de QA necesita una tabla de prueba rápida. Genera una serie del 1 al 20 con columnas: numero, cuadrado (numero²), cubo (numero³) y tipo (par/impar). Usa CASE WHEN para el tipo.
💡 Resultado esperado
┌────────┬──────────┬───────┬─────────┐ │ numero │ cuadrado │ cubo │ tipo │ │ int64 │ int64 │ int64 │ varchar │ ├────────┼──────────┼───────┼─────────┤
Simular carga de CSV con datos generados
Simula un CSV de ventas: crea una tabla "mis_ventas" con 1000 filas (id, fecha, importe, region: Norte/Sur/Este/Oeste). Luego calcula el total por región y el ticket medio global.
Crear base de datos y hacer consultas analíticas
Crea una conexión en memoria con tablas mis_clientes (100 filas) y mis_pedidos (500 filas). Luego haz queries analíticas: cuenta pedidos por estado (GROUP BY), calcula el importe total y ticket medio (SUM, AVG), y busca el top 5 de clientes por número de pedidos (COUNT + ORDER BY + LIMIT).
Regístrate para guardar tu progreso.
## comentarios
Reporta erratas, ayuda a otros o comparte tu opinión. Sé constructivo.
Inicia sesión para comentar y responder.
cargando comentarios...