Ir al contenido
σestadistica.ar

estadistica.ar · Enciclopedia de Estadística en españolhttps://estadistica.ar/conceptos/estadistica-en-sql

M16 · CómputoIntermedioProcedimiento

Estadística en SQL: qué hace cada motor por defecto

Promedios, tasas, uniones y valores vacíos en SQLite, PostgreSQL y DuckDB: la misma consulta, tres motores, y los resultados que cambian sin avisar.

Por Jorge Luis Montivero, Licenciado en Estadística · Mu3Sigma

1 · Un lenguaje, varios motores

SQL es el lenguaje con que se consultan las bases de datos. Muchos datos públicos viven en una base antes de llegar a una planilla, y buena parte del trabajo con datos empieza con una consulta: filtrar, agrupar, unir tablas, contar. SQL es un estándar, pero cada programa que lo ejecuta (cada motor) lo interpreta con sus propias reglas, y la misma consulta puede devolver números distintos.

Esta página compara tres:

  • SQLite, que viene adentro de Python, de los celulares y de muchos programas, y guarda toda la base en un archivo.
  • PostgreSQL, el motor más usado en organismos y sistemas web.
  • DuckDB, pensado para análisis de datos, que crece rápido entre quienes trabajan con R y Python.

SQL Server, MySQL y Oracle tienen sus propias reglas y no se verificaron acá: lo que sigue vale para estos tres motores, y para cualquier otro la regla es probar antes de confiar.

2 · Dónde está cada cosa

CálculoSQLitePostgreSQLDuckDB
PromedioAVG(x)AVG(x)AVG(x)
Desvío muestralno tienestddev_samp(x)stddev_samp(x)
Desvío poblacionalno tienestddev_pop(x)stddev_pop(x)
Percentilno tienepercentile_cont(0.25) WITHIN GROUP (ORDER BY x)quantile_cont(x, 0.25)
Medianano tienepercentile_cont(0.5) WITHIN GROUP (ORDER BY x)median(x)
Contar filas / valoresCOUNT(*) / COUNT(x)igualigual
Tasa de un grupo1000.0 * SUM(d) / SUM(n)igualigual
Unir tablasJOIN, LEFT JOINigualigual

stddev(x), sin sufijo, es el muestral en PostgreSQL y en DuckDB: sobre las mismas 12 edades de las otras entradas da 14,62, como R. SQLite no trae ninguna función de desvío ni de percentiles: hay que calcularlos aparte o pasar los datos a otro programa.

3 · Lo que cambia el resultado

La división entera: la tasa que da cero

Entre dos columnas de números enteros, SQLite y PostgreSQL hacen división entera: descartan los decimales. Una tasa de mortalidad infantil escrita como defunciones / nacimientos * 1000 divide 1.235 por 147.081, obtiene 0 y lo multiplica por mil.

SQLitePostgreSQLDuckDB
defunciones / nacimientos * 1000008,40
1000.0 * defunciones / nacimientos8,408,408,40
5 / 2222,5
Interfaz de DuckDB con la consulta de la tasa de Buenos Aires: con división decimal da 8,3967; con división entera da 0.
En DuckDB, la barra divide con decimales y la doble barra (//) hace la división entera. SQLite y PostgreSQL hacen con la barra simple lo que DuckDB hace con la doble: la tasa de Buenos Aires da 0.

El arreglo es que uno de los términos sea decimal antes de dividir. Lo más simple es poner 1000.0 adelante, como en la segunda fila. El orden importa: defunciones / nacimientos * 1000.0 sigue dando cero, porque la división entera ya ocurrió.

Convertir el tipo también funciona, pero no igual en todos lados:

SQLitePostgreSQLDuckDB
CAST(defunciones AS NUMERIC) / nacimientos * 100008,408,40
CAST(defunciones AS REAL) / nacimientos * 10008,408,408,40

Para SQLite, un entero ya es «numérico», así que NUMERIC no cambia nada: hace falta REAL.

Promediar tasas no da la tasa del grupo

AVG(tasa) promedia las tasas de las provincias como si todas pesaran lo mismo. La tasa de una región es el total de defunciones sobre el total de nacimientos:

Interfaz de DuckDB con una consulta agrupada por región: el promedio de las tasas y la tasa de la región. NOA 9,45 contra 9,75; Pampeana 7,76 contra 8,13.
En la región Pampeana, el promedio simple de las tasas es 7,76 y la tasa de la región, 8,13: Buenos Aires, con 147.081 nacimientos, pesa en el promedio lo mismo que La Pampa. Los tres motores dan los mismos valores.

Es el mismo problema de la media ponderada, y el mismo que aparece en Power BI cuando se resume una columna de tasas con «Promedio».

El JOIN que duplica filas

Un JOIN devuelve una fila por cada par que coincide. Si una de las tablas tiene varias filas por provincia, la otra se repite, y las sumas se inflan. Al unir las provincias con los aglomerados de la EPH (Buenos Aires tiene cuatro, Santa Fe tres), los nacimientos de la región Pampeana pasan de 230.254 a 785.344:

Interfaz de DuckDB: la suma de nacimientos de la región Pampeana da 230.254 sin unir y 785.344 después de unir con la tabla de aglomerados.
La misma suma antes y después del JOIN. Nada falla: la consulta corre, el número es plausible y está mal por más del triple.

La tasa también se mueve, de 8,13 a 8,24, porque cada provincia queda pesada por su cantidad de aglomerados. La regla práctica: antes de sumar, contar. Si COUNT(*) después del JOIN no da las filas que había antes, la unión multiplicó algo. Ver unir tablas.

NULL no es un valor

En SQL, NULL marca un dato faltante, y las reglas para tratarlo sorprenden:

Consulta, sobre el ingreso con el −9 pasado a NULLResultado
COUNT(*)631
COUNT(p21)601
AVG(p21)$871.719 (promedia los 601)
NULL = NULLni verdadero ni falso

La que más confunde es NOT IN. Si la lista contra la que se compara tiene un NULL, la consulta no devuelve ninguna fila: para SQL, «no está en la lista» no se puede afirmar cuando la lista tiene un valor desconocido.

Interfaz de DuckDB: contar las provincias que no están en una lista que contiene '02' y un NULL da 0; sacando el NULL de la lista da 23.
Las provincias que no están en la lista de exclusión: 0 si la lista trae un NULL, 23 si se lo filtra. Los tres motores coinciden.

NOT EXISTS, o filtrar la lista con WHERE codigo IS NOT NULL, evita el problema. Ver datos faltantes.

Códigos como texto y como número

Los códigos del INDEC tienen un cero adelante («06»). Guardados como texto en una tabla y como número en otra, la unión se comporta distinto según el motor:

JOIN de «06» (texto) con 6 (número)Resultado
SQLiteune las 24 provincias: convierte el texto a número
DuckDBune las 24 provincias
PostgreSQLerror: «operator does not exist: character varying = integer»

El error de PostgreSQL es el mejor de los tres resultados: obliga a decidir. Los que convierten solos dan el número correcto acá, pero esconden el problema. Y un código guardado como texto sin el cero se ordena como texto: «10», «14», «18», «2»… en los tres motores.

El redondeo depende del tipo

ROUND(2.5) da 3 en los tres motores cuando el número es decimal exacto. En PostgreSQL, si el número es de punto flotante (float8), da 2: redondea al par, como R y Python. La misma función, en el mismo motor, redondea distinto según cómo esté guardada la columna. Ver redondeo.

Los percentiles

PostgreSQL y DuckDB ofrecen dos percentiles. El continuo (percentile_cont, quantile_cont) interpola, y para el primer cuartil de las 12 edades da 30,75, igual que R y Excel. El discreto (percentile_disc, quantile_disc) devuelve siempre un valor de los datos: 30. Ver cuantiles.

4 · Hasta dónde llega

SQL es la mejor herramienta para preparar los datos: filtrar, unir, agrupar y resumir millones de filas sin cargarlas en memoria. No tiene pruebas de hipótesis ni modelos. El flujo habitual es resumir en SQL y analizar en R o Python, que se conectan a cualquiera de estos motores; DuckDB, además, consulta directamente archivos CSV y Parquet sin importarlos.

5 · Errores frecuentes

  • Dividir dos enteros. En SQLite y PostgreSQL, la tasa da cero. Un 1000.0 adelante lo resuelve; en SQLite, CAST(... AS NUMERIC) no.
  • Promediar tasas. La tasa de un grupo es SUM sobre SUM, no AVG.
  • Sumar después de un JOIN sin contar filas. Si la unión multiplicó filas, las sumas también.
  • Usar NOT IN contra una lista con NULL. No devuelve nada.
  • Comparar con = NULL. Nunca es verdadero: se usa IS NULL.
  • Confiar en COUNT(columna) como total de casos. No cuenta los NULL; COUNT(*) sí.
  • Guardar códigos como número. Se pierde el cero adelante y se rompen las uniones con tablas que lo tienen.
  • Esperar desvío o percentiles en SQLite. No los trae.

Seguir leyendo

Cómo citar: Montivero, J. L. (2026). Estadística en SQL: qué hace cada motor por defecto. estadistica.ar. https://estadistica.ar/conceptos/estadistica-en-sql

estadistica.ar es gratuita y sin publicidad. Si te sirvió, podés invitar un cafecito por transferencia al alias mu3sigma. Asesoramiento estadístico, encuestas y capacitaciones: m3s.pro · WhatsApp +54 9 383 499-7929.

Cómo citar esta entrada

APA (7.ª edición)

Montivero, J. L. (2026). Estadística en SQL: qué hace cada motor por defecto. estadistica.ar. https://estadistica.ar/conceptos/estadistica-en-sql

BibTeX

@misc{estadistica_ar_estadistica_en_sql,
  author       = {Montivero, Jorge Luis},
  title        = {{Estadística en SQL: qué hace cada motor por defecto}},
  year         = {2026},
  howpublished = {\url{https://estadistica.ar/conceptos/estadistica-en-sql}},
  note         = {estadistica.ar. Consultado el \today},
  urldate      = {2026-10-01}
}

Última actualización: 1 de octubre de 2026. El contenido está bajo licencia CC BY-NC-SA 4.0: se puede reutilizar citando la fuente y sin fines comerciales.