Earn the coveted Fabric Analytics Engineer certification. 100% off your exam for a limited time only!
Tenía curiosidad de si se puede hacer lo siguiente en DAX.
Tengo estos productos con una gama.
Id | Empezar | Final |
A | 1 | 5 |
B | 1 | 2 |
Y quería cambiar esta tabla de tal manera que generara un registro por paso del rango.
Id | Nivel |
A | 1 |
A | 2 |
A | 3 |
A | 4 |
A | 5 |
B | 1 |
B | 2 |
¿Se puede hacer esto dinámicamente? Al igual que cuando el comienzo es 2, comienza en la segunda tabla de 2 también.
Solved! Go to Solution.
Ciertamente puede hacerlo en DAX, o en Power Query para el caso.
En DAX, el código se vería algo como esto:
ModifiedTable =
SELECTCOLUMNS (
GENERATE (
YourTable,
GENERATESERIES ( YourTable[Start], YourTable[End] )
),
"Id", YourTable[Id],
"Level", [Value]
)
Alternativamente, en Power Query haría algo similar, agregando una columna que contiene una lista de números .[Inicio]. [Finalizar] y expandiendo eso a filas.
saludos
Owen
Hola, @DouweMeer
Según su descripción, creé datos para reproducir su escenario. El archivo pbix se adjunta al final.
Mesa:
Para no modificar los datos sin procesar, puede ir a 'Editor de consultas', duplicar 'Tabla', pegar los siguientes códigos m en 'Advanced Editor'.
let
Source = Table.FromRows(Json.Document(Binary.Decompress(Binary.FromText("i45WclTSUTIEYlOlWJ1oJScoz0gpNhYA", BinaryEncoding.Base64), Compression.Deflate)), let _t = ((type nullable text) meta [Serialized.Text = true]) in type table [Id = _t, Start = _t, End = _t]),
#"Changed Type" = Table.TransformColumnTypes(Source,{{"Id", type text}, {"Start", Int64.Type}, {"End", Int64.Type}}),
#"Added Custom" = Table.AddColumn(#"Changed Type", "Level", each let s=[Start],e=[End] in
List.Generate(
()=>s,
each _<e+1,
each _+1
)),
#"Expanded Custom" = Table.ExpandListColumn(#"Added Custom", "Level"),
#"Removed Columns" = Table.RemoveColumns(#"Expanded Custom",{"Start", "End"})
in
#"Removed Columns"
Resultado:
Saludos
Allan
Si este post ayuda,entonces considere Aceptarlo como la solución para ayudar a los otros miembros a encontrarlo más rápidamente.
Su solución está en M, la solicité en DAX. Si me encuentras una solución en DAX... sólo entonces usted puede aceptar su comentario como una solución.
Ciertamente puede hacerlo en DAX, o en Power Query para el caso.
En DAX, el código se vería algo como esto:
ModifiedTable =
SELECTCOLUMNS (
GENERATE (
YourTable,
GENERATESERIES ( YourTable[Start], YourTable[End] )
),
"Id", YourTable[Id],
"Level", [Value]
)
Alternativamente, en Power Query haría algo similar, agregando una columna que contiene una lista de números .[Inicio]. [Finalizar] y expandiendo eso a filas.
saludos
Owen
Gracias por la respuesta. Lo he probado, pero estoy luchando con el contexto de las generateseries, ya que espera un valor escalar y en su contexto implícito no hay ninguna referencia a un valor específico del registro. Así que espero que lo siguiente tenga en cuenta los valores específicos de nivel de registro.
así que... eso es como 7 millones de registros vs aproximadamente 365 registros en generateseries... Volveré mañana para ver si los resultados son satisfactorios.
@DouweMeer sólo en el código DAX que publicó: Creo que la línea 7 debe ser cambiado a
GENERATESERIES ( [Inicio], [Fin], 1 )
Esto se debe a que GENERATE recorre en iteración las filas del 1er argumento (t1 en su caso) y evalúa la expresión de tabla en el 2o argumento en ese contexto de fila, por lo que [Start] y [End] hacen referencia a los valores de las filas specifix de t1. Usando MINX y MAXX de la manera que usted tiene daría valores máximos y mínimos generales que no es lo que desea.
Parece que tengo que corregirme en el error de argumento "en blanco". Parece, inexplicablemente, que mi conjunto de datos contiene espacios en blanco en la posición de inicio o fin. Lo estoy intentando de nuevo. Parece tener más dificultades con la expresión esta vez...
HI de nuevo @DouweMeer
Eso es bueno saber que hay algunos valores de inicio/ fin en blanco - entonces es un caso de manejarlos adecuadamente 🙂
También en el código que publicó justo antes de que parecía que había STRUCT_LI_ID en lugar de inicio del producto - es posible que ya lo haya corregido.
En cualquier caso, podría probar el código siguiente para eliminar los valores de inicio/fin en blanco y ver si eso al menos produce un resultado.
Si es necesario, puede ajustar esto para reemplazar Inicio/Fin en blanco con un valor adecuado.
Contract line Date Table =
VAR t1 =
CALCULATETABLE (
SELECTCOLUMNS (
'Model N - Contract Line',
"Line Id", 'Model N - Contract Line'[STRUCT_LI_ID],
"Start", 'Model N - Contract Line'[Product Start],
"End", 'Model N - Contract Line'[Product End]
),
// Eliminate blank Start/End for now
NOT ISBLANK ( 'Model N - Contract Line'[Product Start] ),
NOT ISBLANK ( 'Model N - Contract Line'[Product End] )
)
RETURN
SELECTCOLUMNS (
GENERATE ( t1, GENERATESERIES ( [Start], [End], 1 ) ),
"Line Id", [Line Id],
"Level", [Value]
)
saludos
Owen
Eso es simplemente increíble....
Tuve que crear una tabla independiente, ya que se agotó de mi memoria de 32 GB después de ejecutar la expresión con bastante rapidez :).
Una cosa...
éste...:
CALCULATETABLE (
SELECTCOLUMNS (
'Model N - Contract Line',
"Line Id", 'Model N - Contract Line'[STRUCT_LI_ID],
"Start", 'Model N - Contract Line'[Product Start],
"End", 'Model N - Contract Line'[Product End]
),
// Eliminate blank Start/End for now
NOT ISBLANK ( 'Model N - Contract Line'[Product Start] ),
NOT ISBLANK ( 'Model N - Contract Line'[Product End] )
)
Se puede escribir como tal (¿o hay una ventaja de rendimiento que no agrega el filtro en el contexto de tabla de las columnas selectas?):
SELECTCOLUMNS (
Filter ( 'Model N - Contract Line',
NOT ISBLANK ( 'Model N - Contract Line'[Product Start] ),
NOT ISBLANK ( 'Model N - Contract Line'[Product End] )
)
"Line Id", 'Model N - Contract Line'[STRUCT_LI_ID],
"Start", 'Model N - Contract Line'[Product Start],
"End", 'Model N - Contract Line'[Product End]
)
A propósito...
¿Por qué la gente se siente como poner la coma al final de la línea más bien en frente? ¿Alguna razón particular para esto que no sepa?
Me alegro de que la lógica DAX funcione, incluso si puede que no funcione lo suficientemente bien en el conjunto de datos completo. Tal vez esta tabla podría construirse con Power Query o más ascendente.
Sobre la cuestión de si utilizar FILTER o CALCULATETABLE:
Por lo general, es mejor aplicar FILTER a tablas de tan pequeña cardinalidad como sea posible. FILTER recorre en iteración fila la tabla proporcionada y evalúa el 2o argumento para cada fila.
Así que esta expresión podría ser bastante costosa, ya que recorre en iteración todas las filas de 'Modelo N - Línea de contrato':
FILTER( 'Model N - Contract Line', ... )
En la versión CALCULATETABLE, las dos expresiones
NOT ISBLANK ( 'Model N - Contract Line'[Product Start] ),
NOT ISBLANK ( 'Model N - Contract Line'[Product End] )
en realidad se convierten a
FILTER (
ALL ( 'Model N - Contract Line'[Product Start] ),
NOT ISBLANK ( 'Model N - Contract Line'[Product Start] )
),
FILTER (
ALL ( 'Model N - Contract Line'[Product End] ),
NOT ISBLANK ( 'Model N - Contract Line'[Product End] )
)
lo que da como resultado dos iteraciones: sobre todos los valores de Inicio del producto y todos los valores de Product End, que supongo que podrían ser un número total menor de iteraciones que toda la tabla.
En este artículo se trata bien el tema:
https://www.sqlbi.com/articles/filter-vs-calculatetable-optimization-using-cardinality-estimation/
En cuanto a las comas iniciales o finales, sé que muchos siguen las convenciones de DAX Formatter con comas finales. Sin embargo, ciertamente conozco a algunas personas que prefieren comas principales también. Supongo que se reduce a la preferencia.
saludos
Owen
@OwenAuger Por lo que veo es que cuando me levanto a la parte de generación...
Contract line Date Table =
VAR t1 = SELECTCOLUMNS( 'Model N - Contract Line' , "Line Id" , 'Model N - Contract Line'[STRUCT_LI_ID] , "Start" , 'Model N - Contract Line'[STRUCT_LI_ID] , "End" , 'Model N - Contract Line'[Product End] )
RETURN
SELECTCOLUMNS(
GENERATE(
t1
, GENERATESERIES( [
en este contexto, no se puede 'encontrar ningún valor de campo". El valor esperado por él es escalar en lugar de una columna.
Como puede ver, el [Inicio] y [Fin] no se recoge ya que el contexto de nivel de fila no se reconoce en esta parte de la expresión.
Continuando con la expresión...
Contract line Date Table =
VAR t1 = SELECTCOLUMNS( 'Model N - Contract Line' , "Line Id" , 'Model N - Contract Line'[STRUCT_LI_ID] , "Start" , 'Model N - Contract Line'[STRUCT_LI_ID] , "End" , 'Model N - Contract Line'[Product End] )
RETURN
SELECTCOLUMNS(
GENERATE(
t1
, GENERATESERIES( [Start] , [End] , 1 )
)
, "Line Id" , [Line Id]
, "Level" , [Value]
)
Devolverá el error 'Los argumentos de GenerateSeries no pueden estar en blanco'. De alguna manera hay que especificar que tiene que tomar el valor del contexto de registro de la primera tabla en generar. Con la expresión actual no parece posible.