Saltar al contenido

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.ps1
3pip install duckdb
4python -c "import duckdb; print(f'DuckDB {duckdb.__version__} instalado correctamente')"

Instalación en Windows

1# 🍎 Mac (Terminal/zsh)
2source venv/bin/activate
3pip install duckdb
4python -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 duckdb
2
3# Modo 1: En memoria (datos temporales)
4con = duckdb.connect()
5result = con.sql("SELECT 42 AS respuesta, CURRENT_DATE AS hoy")
6print(result)
7
8# 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 duckdb
2
3con = duckdb.connect()
4
5# Generar 10 clientes ficticios
6result = con.sql("""
7 SELECT
8 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_total
12 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 duckdb
2
3con = duckdb.connect()
4
5# Cargar un CSV en una tabla (DuckDB infiere TODO)
6con.sql("""
7 CREATE TABLE ventas AS
8 SELECT * FROM read_csv_auto('datos/ventas_2024.csv')
9""")
10
11# ¿Qué tipos detectó?
12con.sql("DESCRIBE ventas").show()
13
14# Primera query analítica
15con.sql("""
16 SELECT
17 region,
18 COUNT(*) AS num_ventas,
19 SUM(importe)::INTEGER AS total,
20 ROUND(AVG(importe), 2) AS ticket_medio
21 FROM ventas
22 GROUP BY region
23 ORDER BY total DESC
24""").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 duckdb
2
3con = duckdb.connect('ecommerce.duckdb')
4
5# Categorías
6con.sql("""
7 CREATE OR REPLACE TABLE categorias AS
8 SELECT * FROM (VALUES
9 (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""")
16
17# Productos (200 productos con categoria_id)
18con.sql("""
19 CREATE OR REPLACE TABLE productos AS
20 SELECT
21 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 stock
27 FROM generate_series(1, 200) AS t(i)
28""")
29
30# Clientes (1000)
31con.sql("""
32 CREATE OR REPLACE TABLE clientes AS
33 SELECT
34 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_vip
41 FROM generate_series(1, 1000) AS t(i)
42""")
43
44# Pedidos (5000 con producto_id)
45con.sql("""
46 CREATE OR REPLACE TABLE pedidos AS
47 SELECT
48 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 estado
57 FROM generate_series(1, 5000) AS t(i)
58""")
59
60# Líneas de pedido (detalle de cada pedido)
61con.sql("""
62 CREATE OR REPLACE TABLE lineas_pedido AS
63 SELECT
64 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_unitario
69 FROM generate_series(1, 10000) AS t(i)
70""")
71
72print('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 duckdb
2
3con = duckdb.connect('ecommerce.duckdb')
4
5# Si ves resultados, tu entorno local funciona perfectamente
6con.sql("""
7 SELECT
8 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_medio
13 FROM clientes c
14 LEFT JOIN pedidos p ON p.cliente_id = c.id
15 WHERE p.estado = 'completado'
16 GROUP BY c.ciudad
17 ORDER BY gasto_total DESC
18""").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

[01]

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.

Cargando editor...
[02]

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 │
├────────┼──────────┼───────┼─────────┤
Cargando editor...
[03]

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.

Cargando editor...
[04]

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).

Cargando editor...

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...