Cómo conectar DuckDB a Google Sheets
Consulta datos de Google Sheets con DuckDB SQL usando Python y la API de Sheets. Ejecuta joins, agregaciones y GROUP BY en datos de hojas de cálculo en vivo con menos de 50 líneas de código.
Google Sheets es donde viven tus datos. DuckDB es donde sucede el análisis SQL serio. Esta guía conecta ambos - para que puedas ejecutar GROUP BY, funciones de ventana y joins multitabla contra tus datos de hojas de cálculo en vivo, y luego escribir los resultados en una nueva hoja. Al final, tendrás un script de Python funcional que lee desde Sheets hacia una instancia DuckDB en memoria, la consulta y devuelve los resultados.
Lo que necesitarás
- Python 3.9+ instalado localmente
- Un proyecto de Google Cloud con la API de Sheets habilitada
- Una Cuenta de Servicio de Google con un archivo de credenciales JSON descargado
- Familiaridad básica con SQL y ejecución de scripts de Python desde terminal
- Una hoja de Google con datos tabulares (encabezados de columna en fila 1)
Guía paso a paso
Instala las dependencias de Python
Instala los 3 paquetes que necesita este pipeline: duckdb para el motor SQL, gspread para el wrapper de la API de Sheets, y google-auth para autenticación de cuenta de servicio. bash pip install duckdb gspread google-auth
duckdb0.10+ es recomendado - versiones anteriores no tienen algunas mejoras de parseo de CSVgspread6.x cambió su API de autenticación; confirma que estés en 6.x conpip show gspreadgoogle-authmaneja la renovación de token OAuth automáticamente - no necesitas gestionar tokens manualmente
Pro Tip
Usa un entorno virtual (python -m venv venv && source venv/bin/activate) para mantener estas dependencias aisladas de tu Python del sistema.Crea una Cuenta de Servicio de Google
Una cuenta de servicio permite que tu script se autentique como una identidad no humana que puede leer y escribir hojas de cálculo sin interacción del usuario - esencial para scripts que se ejecutan en horarios o en servidores.
- Ve a Google Cloud Console → IAM & Admin → Service Accounts
- Haz clic en Create Service Account y nómbrala algo como
duckdb-sheets-connector - Salta la asignación de rol IAM opcional - los permisos se controlan a nivel de hoja de cálculo
- Bajo la pestaña Keys de la cuenta de servicio, haz clic en Add Key → Create new key → JSON
- Guarda el archivo
.jsondescargado comocredentials.jsonen tu directorio de proyecto
Pro Tip
Nunca hagas commit decredentials.json a un repositorio git. Agrégalo a .gitignore inmediatamente.Comparte tu hoja de cálculo con la Cuenta de Servicio
La cuenta de servicio tiene una dirección de correo (visible en el archivo JSON bajo client_email, formato: [email protected]). Google Sheets la trata como cualquier otro usuario.
- Abre la hoja de cálculo que deseas consultar
- Haz clic en Share y pega la dirección de correo de la cuenta de servicio
- Otorga acceso de Editor (requerido si deseas escribir resultados; Viewer funciona para solo lectura)
- Copia el ID de la hoja de cálculo desde la URL - es la cadena larga entre
/d/y/edit
Carga datos de Sheets en DuckDB
Google Sheets devuelve datos como un arreglo 2D de strings. El código a continuación obtiene una hoja de trabajo nombrada, la convierte en una lista de diccionarios usando la primera fila como encabezados, y luego la registra como una relación DuckDB. python import duckdb import gspread from google.oauth2.service_account import Credentials SCOPES = ["https://www.googleapis.com/auth/spreadsheets"] SPREADSHEET_ID = "your-spreadsheet-id-here" WORKSHEET_NAME = "Sheet1" # Autentica y abre la hoja de cálculo creds = Credentials.from_service_account_file("credentials.json", scopes=SCOPES) gc = gspread.authorize(creds) sheet = gc.open_by_key(SPREADSHEET_ID).worksheet(WORKSHEET_NAME) # Obtén todos los registros como lista de diccionarios records = sheet.get_all_records() # Usa fila 1 como encabezados de columna automáticamente # Carga en DuckDB con = duckdb.connect() con.register("sheet_data", duckdb.from_arrow( __import__("pyarrow").Table.from_pylist(records) ))
get_all_records()devuelve cada fila como un diccionario - una hoja de 1,000 filas tarda aproximadamente 300ms sobre la API- El método
register()de DuckDB hace que los datos sean consultables sin copiarlos al disco - Los tipos de columna se infieren de los datos; strings parecidas a números se convierten automáticamente a
DOUBLE
Pro Tip
Para hojas con más de 5,000 filas, considera hacer batch consheet.get('A1:Z5000') y sheet.get('A5001:Z10000') para mantenerse dentro de los límites de tamaño por solicitud de la API de Sheets.Ejecuta consultas SQL contra tus datos de Sheets
Una vez que los datos están registrados, escribes SQL estándar. DuckDB soporta funciones de ventana, CTEs, joins LATERAL y la mayoría de sintaxis compatible con PostgreSQL - ninguno de los cuales existe en fórmulas de Sheets. python # Ejemplo de agregación: ingresos totales por región result = con.execute(""" SELECT region, COUNT(*) AS deal_count, SUM(CAST(revenue AS DOUBLE)) AS total_revenue, AVG(CAST(revenue AS DOUBLE)) AS avg_deal_size FROM sheet_data WHERE status = 'Closed Won' GROUP BY region ORDER BY total_revenue DESC """).fetchdf() print(result)
- DuckDB procesa 10 millones de filas en menos de 2 segundos en una laptop - significativamente más rápido que una tabla dinámica con los mismos datos
fetchdf()devuelve un pandas DataFrame; usafetchall()para una lista simple de tuplas- Las columnas de texto desde Sheets a menudo necesitan un
CASTexplícito - Sheets no aplica tipos, así querevenuepodría llegar como"$12,000"en lugar de12000
Pro Tip
Limpia datos sucios de Sheets en SQL usandoREPLACE(REPLACE(revenue, '$', ''), ',', '') antes de hacer cast. Más fácil que limpiarlo en la hoja misma.Escribe resultados de consultas de vuelta en Google Sheets
Después de ejecutar tu análisis, devuelve el DataFrame de resultado a una hoja de trabajo nueva o existente. El patrón a continuación limpia la hoja de destino y la rescribe completamente - confiable para trabajos programados, aunque no ideal para hojas que las personas están editando activamente. python # Crea o limpia la hoja de trabajo de salida try: output_sheet = gc.open_by_key(SPREADSHEET_ID).worksheet("DuckDB Output") output_sheet.clear() except gspread.exceptions.WorksheetNotFound: output_sheet = gc.open_by_key(SPREADSHEET_ID).add_worksheet( title="DuckDB Output", rows=1000, cols=20 ) # Escribe encabezados + datos headers = result.columns.tolist() rows = result.fillna("").values.tolist() output_sheet.update([headers] + rows)
update()acepta una lista 2D y la escribe empezando desde A1fillna("")convierte NaN a string vacío - la API de Sheets rechaza el tipoNaNde Python- La cuota de la API de Sheets es de 300 solicitudes de escritura por minuto por proyecto; para conjuntos de resultados grandes, usa
batch_update()en lugar de eso
Automatiza el pipeline
Un script de una sola vez es útil. Uno programado es un pipeline de datos. Envuelve la lógica en una función y ejecútala en un horario cron para mantener tu hoja de salida actualizada. python import schedule import time def refresh_analysis(): records = sheet.get_all_records() con.register("sheet_data", duckdb.from_arrow( __import__("pyarrow").Table.from_pylist(records) )) result = con.execute(""" SELECT region, SUM(revenue) as total FROM sheet_data GROUP BY region """).fetchdf() output_sheet.clear() output_sheet.update([result.columns.tolist()] + result.fillna("").values.tolist()) print(f"Actualizado a las {__import__('datetime').datetime.now()}") schedule.every(30).minutes.do(refresh_analysis) while True: schedule.run_pending() time.sleep(60)
- Ejecuta esto en una VM pequeña (una instancia de $5/mes lo maneja fácilmente) para mantener tu dashboard de Sheets en vivo
- Según la documentación de la API de Sheets de Google, las solicitudes de lectura están limitadas a 300 por minuto por proyecto - un intervalo de actualización de 30 minutos te mantiene bien dentro de la cuota
- Para uso en producción, agrega manejo de errores alrededor de las llamadas de API y registra fallos en una hoja de monitoreo separada
Pro Tip
Almacena el ID de hoja de cálculo y nombres de hojas de trabajo en variables de entorno (os.environ.get("SPREADSHEET_ID")) en lugar de hardcodearlos. Hace el script reutilizable en proyectos.Conclusión
Has conectado DuckDB a Google Sheets: obtienen datos en vivo a través de la API de Sheets, los carga en una instancia DuckDB en memoria, ejecuta SQL que las fórmulas de Sheets no pueden tocar y escribe resultados de vuelta. El mismo patrón escala a múltiples hojas de trabajo, joins entre hojas y pipelines programados que mantienen una pestaña de reportes actualizada sin ningún export manual.\n\nLa fricción que esto expone es real: cada vez que tu hoja de origen cambia esquema (alguien renombra una columna, agrega una pestaña), tu SQL se rompe silenciosamente. Ese es el vacío entre análisis ad hoc y un pipeline de datos apropiado. Si estás enfrentando ese problema repetidamente en un modelo complejo, vale la pena revisar ModelMonkey - mantiene la capa de consulta DuckDB dentro de Sheets donde tus colaboradores pueden ver qué se está ejecutando.
Preguntas frecuentes
¿Necesito publicar mi hoja de Google en la web para consultarla con DuckDB?
No. El enfoque de cuenta de servicio se autentica a través de OAuth - tu hoja permanece privada y compartida solo con el correo de la cuenta de servicio. La publicación en la web solo es necesaria si estás usando la función read_csv de DuckDB para obtener una URL de exportación pública directamente, lo que omite la autenticación por completo pero expone tus datos públicamente.
¿Cuántas filas puede manejar DuckDB desde Google Sheets?
DuckDB en sí maneja cientos de millones de filas en memoria (limitado por RAM, no por DuckDB). El cuello de botella práctico es la API de Sheets: get_all_records() en una hoja de 50,000 filas toma 3-8 segundos e incide en límites de carga útil. La propia documentación de Google señala que Sheets está limitado a 10 millones de celdas por hoja de cálculo. Para hojas superiores a ~20,000 filas, agrupa tus llamadas a get() o exporta a CSV primero, luego usa duckdb.read_csv() directamente.
¿Puedo unir datos de dos hojas de Google diferentes en una sola consulta DuckDB?
Sí. Obtén cada hoja en una lista separada de diccionarios, registra cada una como una relación DuckDB diferente (con.register("orders", ...), con.register("customers", ...)), y luego únelas con SQL estándar. DuckDB maneja la unión en memoria - no se necesita servidor de base de datos.
¿Qué sucede si una columna en mi hoja tiene tipos mixtos (algunas celdas números, algo texto)?
DuckDB infiere tipos de columna de la muestra de datos. Si una columna tiene tipos mixtos, por defecto se establece en VARCHAR. Deberás hacer cast explícitamente en tu SQL: CAST(TRY_CAST(revenue AS DOUBLE) AS DOUBLE). La variante TRY_CAST devuelve NULL en lugar de lanzar error en valores inconvertibles, que es más seguro para datos sucios de Sheets.
¿Hay alguna manera de consultar Google Sheets con DuckDB sin Python?
La función read_csv de DuckDB puede obtener cualquier URL de CSV pública directamente: SELECT * FROM read_csv('https://docs.google.com/spreadsheets/d/{ID}/export?format=csv'). Esto requiere que la hoja se publique o se comparta públicamente. Para hojas privadas, Python con una cuenta de servicio es el único camino soportado a partir de marzo de 2026.