Hola, tenemos la respuesta a tu búsqueda, desplázate y la encontrarás más abajo.
Solución:
Cuando CALCULATE
se usa en un contexto de fila, la transición ocurrirá donde cada fila se convierte en un filtro y toda la tabla se escanea para cada fila, usando todas las columnas de la fila como filtro. Esto tendrá un impacto en el rendimiento y también podría causar resultados inesperados si su tabla tiene duplicados.
Es posible que las dos versiones que ha proporcionado devuelvan el mismo valor. Sin embargo, si no es así, probablemente se deba a filas duplicadas en su tabla.
Puede que este artículo le resulte muy útil.
Esta respuesta aborda el uso de CALCULATE
en general y cubre los temas de contexto de filtro, contexto de fila y transición de contexto.
Como se define en la pregunta original, [Measure1] y [Measure2] se comportaría de manera idéntica, según la respuesta original a continuación. Consulte la edición de esta respuesta para obtener un tratamiento más completo de CALCULATE
.
En general, si está mirando una expresión en el contexto de una fila, usará CALCULATE
con un solo argumento para provocar una transición de contexto (contexto de fila -> contexto de filtro).
Un error común para principiantes que veo es redundante / innecesario CALCULATE
s en expresiones. CALCULATE
debe usarse solo cuando desee afectar el contexto de filtro del primer argumento. Esto toma dos formas generales:
- Desea utilizar args 2-N para agregar, eliminar o cambiar el contexto del filtro.
- Desea hacer la transición del contexto de la fila para filtrar el contexto.
Los dos pueden unirse.
Un corolario de lo anterior es que nunca debe usar CALCULATE
con un argumento a menos que el sitio de llamada esté en un contexto de fila.
Editar: basado en comentarios y pregunta actualizada
Parece que hay cierta confusión en esta pregunta. Así que aclararé eso primero, antes de entrar en la transición de contexto.
Nota: donde sea que me refiera CALCULATE
a continuación, también puede leer CALCULATETABLE
, que se comporta de forma casi idéntica. El primero es para expresiones escalares y el segundo es para expresiones de tabla.
Una medida es No solo una expresión DAX con nombre. Una medida es una expresión DAX con nombre con un implícito CALCULATE
envuelto alrededor de él. Por lo tanto, si desea reemplazar una referencia a una medida con su expresión, no solo hace un simple reemplazo de texto, debe escribir CALCULATE (
.
Intento no adivinar los diferentes significados de una pregunta si la forma en que se formula es coherente con ella. Creo que querías preguntar:
¿Cuál es la diferencia entre las siguientes expresiones DAX?
SUM ( 'tab'[col1] )
y
CALCULATE ( SUM ( 'tab'[col1] ) )
Esto es materialmente diferente a la pregunta que hizo, porque estaba preguntando sobre dos medidas completamente definidas, no dos fragmentos de DAX. Las medidas se comportarán de manera idéntica, porque sus expansiones son lógicamente equivalentes:
//Measure 1 definition:
Measure1 = SUM ( 'tab'[col1] )
// Measure 1 expands to the following, and you would use this if you were
// replacing a reference with code:
//Expansion1:
CALCULATE ( SUM ( 'tab'[col1] ) )
//Measure2 definition and expansion:
Measure2 = CALCULATE ( SUM ( 'tab'[col1] ) )
//Expansion2:
CALCULATE ( CALCULATE ( SUM ( 'tab'[col1] ) ) )
Por lo tanto, sus medidas son semánticamente (aunque no textualmente) idénticas. Ambos actúan como SUM
envuelto en un CALCULATE
. [Measure2] simplemente tiene un extra CALCULATE
tras la expansión.
Entonces que hace CALCULATE
¿hacer? Mucho. Como referencia, cuando doy entrenamientos de DAX, CALCULATE
y el filtro y el contexto de fila son un segmento de varias horas.
CALCULATE
hace lo siguiente.
-
Realiza la transición de contexto. Crea un nuevo contexto de filtro dentro del cual evaluar su primera expresión de argumento. Este nuevo contexto de filtro consta de lo siguiente (combinado en un contexto de filtro único):
una. Cualquiera que sea el contexto de filtro externo que exista en el sitio de llamada de
CALCULATE
B. Cualquiera que sea el contexto de fila que exista en el sitio de llamada de
CALCULATE
-
Evalúa args 2-N (conocidos como setfilters) para modificar (agregar, eliminar o modificar el existente) el contexto del filtro del paso (1), y finalmente
-
Evalúa la expresión en arg1 en el nuevo contexto de filtro determinado por los pasos (1) y (2).
Entonces, esto plantea un par de preguntas, a saber:
- ¿Qué es un contexto de filtro?
- ¿Qué es un contexto de fila?
- ¿Qué significa transformar un contexto de fila en un contexto de filtro?
Entonces, primero, filtre el contexto. El contexto de filtro proviene de varias funciones de DAX, incluidas CALCULATE
, CALCULATETABLE
, SUMMARIZE
, SUMMARIZECOLUMNS
, y GROUPBY
. Esta lista no pretende ser exhaustiva, pero cubre algunas funciones muy comunes.
Siempre que interactúa con un modelo tabular en una herramienta de informes, por ejemplo, tablas dinámicas de Excel o informes de Power BI, sus acciones en la GUI generan consultas que se utilizan para completar cualquier objeto visual. Desde la perspectiva de estas (y otras) herramientas de informes, el contexto del filtro proviene de:
- Etiquetas de fila / columna / eje (no confunda una fila de tabla dinámica para contribuir al contexto de fila, no es así)
- Filtros de tabla dinámica
- Rebanadoras
- Otras selecciones de elementos visuales como filtrado cruzado
- Filtros visuales / de página / de informe / de obtención de detalles / de información sobre herramientas
Puede pensar en el contexto del filtro como un conjunto de ‘Tabla'[Column]-> mapas de valores. Cualquier valor literal que se seleccione o que cumpla con un criterio de selección se convierte en el contexto del filtro.
Por ejemplo, consideremos una matriz visual con ‘Calendario'[Year] en filas, “Calendario”[MonthName] en columnas, un segmentador de ‘Producto'[Category]= “Ropa” y un filtro a nivel de página de ‘Calendario'[Year]> 2015. Veremos el contexto del filtro para una medida, [M], siendo evaluado en la matriz de la tercera fila y cuarta columna (abril de 2018)
Filter Context:
'Calendar'[Year]=2018
'Calendar'[Year]>2015
=> 'Calendar'[Year] IN 2016, 2017, 2018, ..., N // for whatever years exist in the calendar
'Calendar'[Month]="April"
'Product'[Category]="Clothing"
Cada celda de la matriz tendría su propio contexto de filtro basado en la intersección de año y mes, pero el resto permanecería igual. Para la fila del total general en la parte inferior, el contexto del filtro no tendría un año específico de la matriz, pero aún se vería afectado por el filtro de nivel de página. Para la columna de gran total a la derecha, no habría contexto de mes, pero habría un año específico en contexto. Para la celda de concesión total en la parte inferior derecha de la matriz, los únicos filtros serían:
'Product'[Category]="Clothing"
'Calendar'[Year]>2015 //from the page-level
En resumen, el contexto del filtro está bastante alineado con lo que probablemente lo entendiste. He descubierto que para la mayoría de las personas, el filtro de contexto por sí solo tiene sentido.
Ahora para el contexto de la fila. El contexto de fila existe siempre que iteramos una tabla. Encontrará un contexto de fila en dos lugares:
- Al agregar una columna calculada a una tabla
- En una función de iterador, por ejemplo:
- -X funciones (
SUMX
,AVERAGEX
, etc …) FILTER
ADDCOLUMNS
- -X funciones (
Siempre que hablamos de contexto de fila, hablamos de iteración. Puedes pensar en un bucle for como:
//pseudocode
for row in table:
También puede considerar el contexto de fila como análogo a un cursor SQL, iterando las filas de una tabla. Sería en gran parte equivalente a un cursor de solo lectura de avance rápido.
Consideramos una fila a la vez. El contexto de fila consiste en el conjunto de valores literales en las columnas de la tabla que se itera.
Por lo tanto, dada una tabla, ‘T’ con columnas (Id, Cantidad, Fecha), el contexto de la fila en SUMX ( 'T',
. También puede utilizar una función con valores de tabla como primer argumento de un iterador, p. Ej. SUMX ( VALUES ( 'T'[Date] ),
. En este caso, la tabla que iteramos es el retorno de VALUES ( 'T'[Date] )
, que es el conjunto de valores únicos en la 'T'[Date] columna. En este caso, el contexto de la fila consta solo de un valor de 'T'[Date] - el resto de 'T' no está en el contexto de la fila.
Nota: cuando estamos en un contexto de fila, podemos referirnos a una columna por su nombre sin agregarla; esto no es válido en ningún lugar de DAX excepto en un contexto de fila.
Nota 2: Funciones de agregación básicas como SUM
o COUNTROWS
no tiene interacción con el contexto de la fila. Entonces, para la tabla y las expresiones a continuación, veremos resultados que probablemente no tengan significado:
//Table, 'T' with schema as above
(1, 10, 2019-02-01),
(2, 20, 2019-02-01),
(3, 30, 2019-03-01),
(4, 40, 2019-03-02)
//Add calculated column to 'T'
C = SUM ( 'T'[Amount] )
// Result would be 100 on every row - the total of 'T'[Amount]
//Measure on a card visual with no other filters:
M = SUMX ( 'T', SUM ( 'T'[Amount] ) )
// Result would be 400, which is the sum of 'T'[Amount] calculated once per row
// and summed together
//M2 on card with no other filters
M2 = SUMX ( VALUES ( 'T'[Date] ), SUM ( 'T'[Amount] ) )
// Result is 300, which is the sum of 'T'[Amount] calculated once per unique date
// and summed together
Cuando estamos en un contexto de fila y queremos que los valores de la fila contribuyan al contexto de filtro, podemos envolver un agregado en un CALCULATE
para transformar el contexto de fila en un contexto de filtro. Esto se conoce como transición de contexto.
// Same table as above:
M3 = SUMX ( VALUES ( 'T'[Date] ), CALCULATE ( SUM ( 'T'[Amount] ) ) )
// result on card would be 100, the actual total
Podemos dividir el cálculo en la siguiente iteración:
// Input table would be 2019-03-02, 2019-02-01, 2019-03-01
//Iteration1:
1. Row context: 'T'[Date]=2019-03-02
2. CALCULATE transitions 'T'[Date] value to Filter context: 'T'[Date]=2019-03-02
3. SUM is evaluated in filter context from step (2)
4. Result of iteration1 = 40
//Iteration2:
1. Row context: 'T'[Date]=2019-02-01
2. CALCULATE transitions 'T'[Date] value to Filter context: 'T'[Date]=2019-02-01
3. SUM is evaluated in filter context from step (2)
4. Result of iteration1 = 30 //note both [Amount]s for 2019-02-01 contribute to this
//Iteration3:
1. Row context: 'T'[Date]=2019-03-01
2. CALCULATE transitions 'T'[Date] value to Filter context: 'T'[Date]=2019-03-01
3. SUM is evaluated in filter context from step (2)
4. Result of iteration1 = 30
// Final result - combine iteration results with sum:
40 + 30 + 30 = 100
Tenga en cuenta que el contexto de filtro navega automáticamente por las relaciones en el modelo. El contexto de fila consta solo de los valores de la tabla que se itera. Si necesita navegar por una relación en un contexto de fila, puede usar RELATED
o RELATEDTABLE
, o puede transformar el contexto de fila en contexto de filtro con CALCULATE
o CALCULATETABLE
.
Entonces, en su ejemplo vinculado:
Expected Result =
SUMX (
VALUES ( Unique_Manager[Manager] ),
VAR SumBrand = CALCULATE ( SUM ( Budget_Brand[BudgetBrand] ) )
VAR SumProduct = CALCULATE ( SUM ( Budget_Product[BudgetProduct] ) )
RETURN
IF ( ISBLANK ( SumProduct ), SumBrand, SumProduct )
)
SumBrand
es la suma de "Budget_Brand"[BudgetBrand] para el 'Unique_Manager'[Manager] en el contexto de la fila actual, es decir, el administrador que es el valor de la fila actual en iteración. Similar, SumProduct
es la suma de "Budget_Product"[BudgetProduct] para el gerente en el contexto de la fila.
Con la misma facilidad, podría definir lo siguiente:
Brand Budget = SUM ( 'Budget_Brand'[BudgetBrand] )
Product Budget = SUM ( 'Budget_Product'[BudgetProduct] )
Expected Result =
SUMX (
VALUES ( 'Unique_Manager'[Manager] ),
VAR SumBrand = [Brand Budget]
VAR SumProduct = [Product Budget]
RETURN
IF ( ISBLANK ( SumProduct ), SumBrand, SumProduct )
)
Probablemente lo refactorizaría de la siguiente manera, para que solo calcule el presupuesto de la marca si lo necesita:
Expected Result =
SUMX (
VALUES ( 'Unique_Manager'[Manager] ),
VAR SumProduct = [Product Budget]
RETURN
IF ( ISBLANK ( SumProduct ), [Brand Budget], SumProduct )
)
Sin embargo, con o sin esa refactorización, la versión anterior que hace referencia a las medidas es semánticamente idéntica a la versión que inserta CALCULATE ( SUM ( ... ) )
.
Esto se debe a que, como se indicó anteriormente en esta sección editada, los dos siguientes son equivalentes:
Measure = SUM ( 'tab'[col1] )
CALCULATE ( SUM ( 'tab'[col1] ) )
Espero que esto sea útil para comprender por qué fui tan valiente como para responder a su pregunta original como lo hice. Como medidas, sus dos expresiones son semánticamente equivalentes. Como expresiones aisladas, no lo son.
Depende de cómo esté utilizando las expresiones, es decir, COLUMNA CALCULADA vs MEDIDA y en qué contexto. Los contextos de filtro se derivan de filtros activos en su informe, es decir, SLICERS, CROSS FILTER a través de elementos visuales e incluso se pueden propagar a través de relaciones existentes en el modelo. Utilizados en una columna calculada, producirían resultados muy diferentes. Vea la imagen a continuación:
Como puede ver, he proporcionado un conjunto de datos muy básico que muestra los títulos de los puestos y sus respectivos salarios. Cuando se usa la expresión sin el estado de cálculo, no se proporciona un contexto de filtro y ninguno se derivaría implícitamente, por lo que la columna daría como resultado la suma TOTAL para todo el campo 'Salario'. Cuando envolvemos la misma expresión en una declaración de cálculo, proporcionamos un CONTEXTO DE FILA y obtenemos la suma de cada FILA dentro de la tabla. Dos resultados muy distintos.
Cuando se utilizan en una medida, producirán resultados idénticos. Vea la imagen a continuación:
Esto se debe a que la medida SUM () se envolvería con un CALCULATE implícitamente y heredaría la misma funcionalidad que MEASURE que contiene la Sentencia CALCULATE. En este caso, el mapa de árbol se utiliza como un segmentador y proporciona un contexto de filtro para ambas medidas, lo que produce resultados idénticos.
Este ARTÍCULO hace un gran trabajo al explicar los contextos de filas y filtros.
¡¡Espero que esto ayude!!
Si crees que te ha resultado de utilidad nuestro artículo, te agradeceríamos que lo compartas con el resto seniors y nos ayudes a extender este contenido.