Funciones de Agregación
SUM, COUNT, AVERAGE, MIN, MAX y todas sus variantes — los cimientos de cualquier modelo DAX
Principiante
Intermedio
¿Qué son las funciones de agregación? 🤔
Las funciones de agregación toman una columna (o una expresión evaluada fila a fila) y devuelven un único valor escalar. Son el primer tipo de función que aprende cualquier persona en DAX porque son imprescindibles para construir medidas.
La distinción más importante desde el principio: funciones simples vs iteradoras X
SUM([Ventas])— agrega directamente una columna numéricaSUMX(Tabla, Expresión)— itera fila a fila, calcula la expresión, y luego agrega
Analogía kawaii 🌸
SUM es como pedirle a alguien que cuente el dinero en una caja. SUMX es como pedirle que por cada factura calcule (precio × cantidad × descuento) y luego lo sume todo. Mucho más flexible pero también más trabajo.
SUM es como pedirle a alguien que cuente el dinero en una caja. SUMX es como pedirle que por cada factura calcule (precio × cantidad × descuento) y luego lo sume todo. Mucho más flexible pero también más trabajo.
La regla de oro 🏆
Si necesitas hacer un cálculo por fila antes de agregar → usa la versión X (SUMX, AVERAGEX, MAXX...). Si solo necesitas agregar una columna que ya existe → usa la versión simple (SUM, AVERAGE, MAX...).
Si necesitas hacer un cálculo por fila antes de agregar → usa la versión X (SUMX, AVERAGEX, MAXX...). Si solo necesitas agregar una columna que ya existe → usa la versión simple (SUM, AVERAGE, MAX...).
➕
SUM — La función más usada en DAX
SUM(<columna>)
Principiante
Suma todos los valores de una columna numérica en el contexto de filtro actual. La medida más habitual en cualquier modelo.
Ejemplo básico:
// Medida básica de ventas totales
Total Ventas = SUM('Ventas'[Importe])
// En un visual filtrado por "España" → suma solo las ventas de España
// En un visual sin filtro → suma TODAS las ventas
Ejemplo con contexto:
// SUM siempre respeta el contexto de filtro automáticamente
// Si tienes un slicer de País seleccionado en "Francia":
Total Ventas = SUM('Ventas'[Importe]) -- devuelve solo ventas de Francia
// No hace falta escribir nada especial — CALCULATE hace eso automáticamente
⚠️ Importante
SUM solo funciona con columnas numéricas. Para sumar en base a una expresión por fila (ej: precio × cantidad), necesitas SUMX. Y nunca uses SUM dentro de CALCULATE como primer argumento — ahí va una medida o expresión.
SUM solo funciona con columnas numéricas. Para sumar en base a una expresión por fila (ej: precio × cantidad), necesitas SUMX. Y nunca uses SUM dentro de CALCULATE como primer argumento — ahí va una medida o expresión.
SUMX(<tabla>, <expresión>)
Intermedio
Itera cada fila de la tabla, evalúa la expresión en el contexto de esa fila, y suma todos los resultados. Imprescindible cuando no tienes una columna con el importe ya calculado.
Ejemplo — cuando no existe columna de importe:
// Tabla Ventas tiene: Cantidad y PrecioUnitario, pero NO Importe
// ❌ Esto NO funciona:
Total Ventas WRONG = SUM('Ventas'[Cantidad] * 'Ventas'[PrecioUnitario])
// ✅ Esto SÍ funciona:
Total Ventas = SUMX('Ventas', 'Ventas'[Cantidad] * 'Ventas'[PrecioUnitario])
// Por cada fila: calcula Cantidad × PrecioUnitario → suma todo
Ejemplo con descuento:
// Precio con descuento aplicado fila a fila
Total Ventas Neto =
SUMX(
'Ventas',
'Ventas'[Cantidad] * 'Ventas'[PrecioUnitario] * (1 - 'Ventas'[Descuento])
)
Ejemplo con tabla filtrada:
// Suma solo las ventas de productos con margen > 20%
Ventas Alto Margen =
SUMX(
FILTER('Ventas', 'Ventas'[Margen] > 0.20),
'Ventas'[Importe]
)
🏆 Best Practice
SUMX con una tabla grande puede ser lento. Si el cálculo fila a fila es simple (precio × cantidad), suele ser eficiente. Pero si la expresión es compleja, considera crear una columna calculada en el modelo y usar SUM sobre esa columna.
SUMX con una tabla grande puede ser lento. Si el cálculo fila a fila es simple (precio × cantidad), suele ser eficiente. Pero si la expresión es compleja, considera crear una columna calculada en el modelo y usar SUM sobre esa columna.
🔢
COUNT y familia — contar con criterio
Tabla rápida de referencia:
| FUNCIÓN | QUÉ CUENTA | IGNORA BLANCOS | TIPO DE COLUMNA |
|---|---|---|---|
| COUNT | Valores numéricos | ✅ Sí | Solo números |
| COUNTA | Cualquier valor no vacío | ✅ Sí | Cualquier tipo |
| COUNTBLANK | Celdas vacías/BLANK | N/A | Cualquier tipo |
| COUNTROWS | Filas de una tabla | N/A | Tabla completa |
| COUNTX | Expresión no vacía por fila | ✅ Sí | Expresión iterada |
| COUNTAX | Expresión no vacía (cualquier tipo) | ✅ Sí | Expresión iterada |
COUNT(<columna>) | COUNTA(<columna>)
Principiante
Ejemplo COUNT:
// Cuenta cuántas ventas tienen importe registrado (número)
Nº Ventas = COUNT('Ventas'[Importe])
// ¡OJO! Si alguna fila tiene BLANK en Importe, NO la cuenta
// Para contar filas con cualquier dato (texto, fecha, número):
Nº Registros = COUNTA('Ventas'[ID_Venta])
COUNTBLANK(<columna>)
Principiante
Ejemplo:
// Cuántos productos no tienen precio asignado
Productos Sin Precio = COUNTBLANK('Productos'[Precio])
// Útil para auditorías de calidad de datos
COUNTROWS(<tabla>)
Principiante
La más usada para contar filas — no depende del tipo de dato.
Ejemplos:
// Contar todas las filas de la tabla
Nº Pedidos = COUNTROWS('Pedidos')
// Con filtro:
Pedidos Pendientes = COUNTROWS(FILTER('Pedidos', 'Pedidos'[Estado] = "Pendiente"))
// Contar clientes únicos que han comprado (patrón muy común)
Clientes Activos = COUNTROWS(VALUES('Ventas'[ID_Cliente]))
COUNTX(<tabla>, <expresión>)
Intermedio
Ejemplo:
// Contar filas donde el margen calculado es positivo
Ventas Rentables =
COUNTX(
'Ventas',
IF('Ventas'[PrecioVenta] > 'Ventas'[Coste], 1, BLANK())
)
Regla práctica para elegir la función de conteo 💡
¿Quieres contar FILAS de una tabla? → COUNTROWS. ¿Quieres contar VALORES no vacíos de una columna numérica? → COUNT. ¿Valores de cualquier tipo? → COUNTA. ¿Celdas vacías? → COUNTBLANK. ¿Con lógica fila a fila? → COUNTX.
¿Quieres contar FILAS de una tabla? → COUNTROWS. ¿Quieres contar VALORES no vacíos de una columna numérica? → COUNT. ¿Valores de cualquier tipo? → COUNTA. ¿Celdas vacías? → COUNTBLANK. ¿Con lógica fila a fila? → COUNTX.
🎯
DISTINCTCOUNT — Contar únicos
DISTINCTCOUNT(<columna>)
Principiante — Intermedio
Cuenta los valores únicos (distintos) de una columna, ignorando duplicados. Equivale a COUNT(DISTINCT columna) en SQL. Imprescindible para métricas como "número de clientes únicos" o "SKUs vendidos".
Ejemplo básico:
// Cuántos clientes diferentes han comprado
Clientes Únicos = DISTINCTCOUNT('Ventas'[ID_Cliente])
// Si el cliente 001 compró 5 veces → cuenta como 1
// Cuántos productos diferentes se han vendido
SKUs Vendidos = DISTINCTCOUNT('Ventas'[ID_Producto])
// Diferencia importante:
Nº Ventas = COUNTROWS('Ventas') -- número de transacciones (filas)
Clientes Únicos = DISTINCTCOUNT('Ventas'[ID_Cliente]) -- número de compradores únicos
Ticket Medio Clientes = DIVIDE([Total Ventas], [Clientes Únicos])
DISTINCTCOUNTNOBLANK(<columna>)
Intermedio
Igual que DISTINCTCOUNT pero excluye explícitamente los valores BLANK. DISTINCTCOUNT sí incluye el BLANK como un valor distinto en algunos contextos.
Ejemplo:
// Si la columna Región tiene: "Norte", "Sur", BLANK, "Norte"
DISTINCTCOUNT('Ventas'[Región]) -- resultado: 3 (Norte, Sur, BLANK)
DISTINCTCOUNTNOBLANK('Ventas'[Región]) -- resultado: 2 (Norte, Sur)
📏
AVERAGE — Medias y promedios
AVERAGE(<columna>)
Principiante
Calcula la media aritmética de los valores numéricos de una columna. Ignora automáticamente los valores BLANK (no los trata como 0, los excluye del cálculo).
Ejemplo:
// Ticket medio por transacción
Ticket Medio = AVERAGE('Ventas'[Importe])
// Si hay 10 ventas con importes: 100, 200, BLANK, 300...
// AVERAGE ignora el BLANK → media de los 9 valores no vacíos
// ¡OJO! Diferencia importante:
Ticket Medio Real = AVERAGE('Ventas'[Importe])
// vs
Ticket Medio Con Ceros = DIVIDE(SUM('Ventas'[Importe]), COUNTROWS('Ventas'))
// El segundo divide entre TODAS las filas (incluyendo las que tienen BLANK)
// Elige según qué signifique un BLANK en tu contexto
AVERAGEA(<columna>)
Principiante
Como AVERAGE pero también procesa columnas no numéricas. Convierte TRUE=1, FALSE=0, texto=0. Raramente necesaria en Power BI — AVERAGE es suficiente para casi todo.
AVERAGEX(<tabla>, <expresión>)
Intermedio
Versión iteradora de AVERAGE. Calcula la expresión por fila y luego promedia los resultados.
Ejemplo — Margen medio por pedido:
// Media del margen de cada pedido (no el margen total / nº pedidos)
Margen Medio por Pedido =
AVERAGEX(
'Pedidos',
DIVIDE(
SUMX(RELATEDTABLE('LineasPedido'), 'LineasPedido'[Margen]),
SUMX(RELATEDTABLE('LineasPedido'), 'LineasPedido'[Importe])
)
)
🎢
MIN y MAX — Valores extremos
Tabla de referencia:
| FUNCIÓN | QUÉ HACE | TIPO |
|---|---|---|
| MIN | Mínimo de columna numérica/fecha | Simple |
| MINA | Mínimo incluyendo lógicos | Simple (raro) |
| MINX | Mínimo de expresión por fila | Iteradora |
| MAX | Máximo de columna numérica/fecha | Simple |
| MAXA | Máximo incluyendo lógicos | Simple (raro) |
| MAXX | Máximo de expresión por fila | Iteradora |
MIN(<columna>) | MAX(<columna>)
Principiante
Ejemplo MIN/MAX básico:
// Fechas del primer y último pedido
Primera Venta = MIN('Ventas'[Fecha])
Última Venta = MAX('Ventas'[Fecha])
// Precio más bajo y más alto
Precio Mínimo = MIN('Productos'[Precio])
Precio Máximo = MAX('Productos'[Precio])
// Número de días activos (entre primera y última venta)
Días Activos = DATEDIFF(MIN('Ventas'[Fecha]), MAX('Ventas'[Fecha]), DAY)
MINX(<tabla>, <expresión>) | MAXX(<tabla>, <expresión>)
Intermedio
Ejemplo MINX/MAXX:
// El pedido de mayor importe (calculado como precio × cantidad)
Pedido Mayor Importe =
MAXX(
'Pedidos',
SUMX(RELATEDTABLE('LineasPedido'), 'LineasPedido'[Precio] * 'LineasPedido'[Cantidad])
)
// MIN con dos columnas (MIN con dos argumentos devuelve el menor de los dos valores):
Precio Aplicado = MIN('Productos'[Precio], 'Productos'[PrecioOferta])
✖️
PRODUCT y PRODUCTX — Multiplicación acumulada
PRODUCT(<columna>) | PRODUCTX(<tabla>, <expresión>)
Intermedio — Avanzado
Multiplica todos los valores de una columna (o expresión). Poco usada en business intelligence general, pero muy útil en finanzas para cálculos de rendimientos compuestos.
Ejemplo — Rendimiento compuesto:
// Si tienes una tabla con la variación mensual en %:
// Enero +5%, Febrero +3%, Marzo -2%...
// El rendimiento compuesto acumulado es el PRODUCTO de (1 + variación)
Rendimiento Compuesto =
PRODUCTX(
'Rendimientos',
1 + 'Rendimientos'[Variacion_Mensual]
) - 1
// Resultado: el rendimiento total del período considerando el interés compuesto
⚡
APPROXIMATEDISTINCTCOUNT — Velocidad vs Precisión
APPROXIMATEDISTINCTCOUNT(<columna>)
Avanzado
Versión aproximada (pero muy rápida) de DISTINCTCOUNT. Usa el algoritmo HyperLogLog para estimar el conteo distinto con un margen de error de ~2%. Ideal para tablas con millones de filas donde la velocidad importa más que la precisión exacta.
Ejemplo:
// En una tabla con 50 millones de filas:
// ❌ Lento en DirectQuery o tablas enormes:
Visitantes Únicos EXACT = DISTINCTCOUNT('WebLogs'[UserID])
// ✅ Mucho más rápido, ~2% de error (aceptable para dashboards):
Visitantes Únicos APPROX = APPROXIMATEDISTINCTCOUNT('WebLogs'[UserID])
💡 Cuándo usarla
Para la mayoría de casos de negocio donde un error de ±2% es aceptable (conteo de visitantes, usuarios activos, IDs únicos en big data), APPROXIMATEDISTINCTCOUNT puede ser 10-100x más rápido que DISTINCTCOUNT. ¡Úsala sin miedo en métricas de alto volumen!
Para la mayoría de casos de negocio donde un error de ±2% es aceptable (conteo de visitantes, usuarios activos, IDs únicos en big data), APPROXIMATEDISTINCTCOUNT puede ser 10-100x más rápido que DISTINCTCOUNT. ¡Úsala sin miedo en métricas de alto volumen!
🧐
Errores típicos y cómo evitarlos
Error 1 — Usar SUM donde debería ir SUMX:
// ❌ Error: no puedes multiplicar columnas dentro de SUM
Total = SUM('Ventas'[Precio] * 'Ventas'[Cantidad]) -- ERROR de sintaxis
// ✅ Correcto:
Total = SUMX('Ventas', 'Ventas'[Precio] * 'Ventas'[Cantidad])
Error 2 — AVERAGE no es lo mismo que Total/Conteo cuando hay blancos:
// Si el 30% de tus filas tienen BLANK en Importe:
AVERAGE('Ventas'[Importe]) -- divide entre el 70% de filas (las no vacías)
DIVIDE(SUM('Ventas'[Importe]), COUNTROWS('Ventas')) -- divide entre el 100%
// ¿Cuál es correcta? Depende de tu lógica de negocio. ¡Decídelo conscientemente!
Error 3 — DISTINCTCOUNT incluye BLANK:
// Si quieres solo IDs reales sin contar filas sin ID:
DISTINCTCOUNTNOBLANK('Ventas'[ID_Cliente]) -- más seguro
🚀 Siguiente paso
¡Ya dominas las agregaciones! Son la base de todo. El siguiente gran salto es entender cómo CALCULATE modifica el contexto en el que se evalúan estas funciones — eso es lo que hace DAX único y potente.
¡Ya dominas las agregaciones! Son la base de todo. El siguiente gran salto es entender cómo CALCULATE modifica el contexto en el que se evalúan estas funciones — eso es lo que hace DAX único y potente.