添加使用整个 table 计算能力查询或 dax 的计算自定义列

Add calculated custom column using entire table for calculation power query or dax

我在 Power BI 中有此 table,其中包含与某些对象有关的事件


|new_state |object_id | created_at |

|新 |1 |11/4/2015 1:50:48 下午 |

|in_use |3 |11/4/2015 2:31:10 下午 |

|in_use |1 |11/4/2015 2:31:22 下午 |

|已删除 |2 |11/4/2015 3:14:10 下午 |

.....

我正在尝试在 DAX 或 power 查询中添加一个计算列,这样对于每一行我都会有该对象的 previous_state。从逻辑的角度来看,这并不困难:您按 id 分组,并为该组中的每一行查找最接近的先前时间,并获得 "new_state" 代表该行的先前状态。 我尝试通过在 power query 中创建一个函数并在自定义列中使用它来执行此操作,但我收到 "cyclic reference detected" 错误并且无法执行此操作。关于解决方案的任何想法?

肯定有比这更简洁的解决方案,但在 DAX 中,您可以创建一个计算列 (prevdate) 来存储上一个条目的日期时间:

=
CALCULATE (
    MAX ( [created_at] ),
    ALL ( table1 ),
    Table1[created_at] < EARLIER ( [created_at] ),
    Table1[object_id] = EARLIER ( [object_id] ) )

然后您添加另一个计算列来存储之前的状态:

=
CALCULATE (
    VALUES ( Table1[new_state] ),
    ALL ( Table1 ),
    Table1[created_at] = EARLIER ( Table1[prevdate] ),
    Table1[object_id] = EARLIER ( Table1[object_id] )
)

现在很难在 Power Query 中表达行之间的比较。大多数函数假设 table 只是一组无序的行。

要扩展 Oğuz 的评论,您可以添加一个索引列,然后添加一个列 PreviousState 索引到上一行(或空)。作为优化,如果您先缓冲整个 table 可能会快得多。

let
    Source = Table.FromRows(Json.Document(Binary.Decompress(Binary.FromText("i45WqslLLY8vLkksSVWoyU/KSk0uic9MUahRSC5KBYqlxCeWKNQoxepAFCrUGAKRob6JvpGBoamCoZWpgZWJhUKAL0xNZl58aTHQJGNkZUZWxoZWhgZYlBliKDMyQlKWkpqTCnSDQo0RsjpjK0MThHGxAA==", BinaryEncoding.Base64), Compression.Deflate)), let _t = ((type text) meta [Serialized.Text = true]) in type table [Column1 = _t]),
    #"Split Column by Delimiter" = Table.SplitColumn(Source,"Column1",Splitter.SplitTextByDelimiter("|", QuoteStyle.Csv),{"Column1.1", "Column1.2", "Column1.3", "Column1.4", "Column1.5"}),
    #"Removed Columns" = Table.RemoveColumns(#"Split Column by Delimiter",{"Column1.1", "Column1.5"}),
    #"Trimmed Text" = Table.TransformColumns(#"Removed Columns",{},Text.Trim),
    #"Promoted Headers" = Table.PromoteHeaders(#"Trimmed Text"),
    ChangedType = Table.TransformColumnTypes(#"Promoted Headers",{{"object_id", Int64.Type}, {"created_at", type datetime}, {"new_state", type text}}),
    #"Added Index" = Table.AddIndexColumn(ChangedType, "Index", 0, 1),
    Buffer = Table.Buffer(#"Added Index"),
    #"Added Custom" = Table.AddColumn(Buffer, "PreviousState", each try Buffer{[Index] - 1}[created_at] otherwise null),
    #"Inserted Time Subtraction" = Table.AddColumn(#"Added Custom", "TimeDifference", each [created_at] - [PreviousState], type duration)
in
    #"Inserted Time Subtraction"

我已经解决了:D

#"Sorted Rows" = Table.Sort(#"Reordered Columns",{{"object_id", Order.Ascending}, {"created_at", Order.Ascending}}),
#"Added Index" = Table.AddIndexColumn(#"Sorted Rows", "Index", 0, 1),
Buffer = Table.Buffer(#"Added Index"),
#"Added Custom" = Table.AddColumn(Buffer, "PreviousState", each try (if Buffer{[Index] - 1}[object_id]=Buffer{[Index]}[object_id] then Buffer{[Index] - 1}[new_state] else null ) otherwise null)

我不确定这主要是不是黑客攻击,但它似乎有效。您是否看到它将来可能会失败的任何一点?