PowerQuery - 根据给定值和当前日期查找最近日期

PowerQuery - Finding Most Recent Date Based on Given Value and Current Date

我有一个名为 'Table1' 的 table,它有两列,分别是 'Name' 和 'Date'。

在 Power Query 编辑器中,我想创建一个名为 'Last Date' 的自定义列来查找给定名称上次出现的最近日期。

例如,B 首次出现在 5/7/2019,然后出现在 11/8/2019,最后出现在 17/9/2019。因此,当日期为 11/8/2019 时,B 的最后日期为 5/7/2019,而当日期为 17/9/2019 时,B 的最后日期为 11/8/2019。请看下面的例子。

我在网上做了一些研究,但对自定义函数、VAR、Measure、MAXX、CALCULATE、FILTER 等感到困惑...

我不熟悉 DAX 或高级 DAX 编辑器,所以如果可能请提供详细的答案或明确的步骤来应用您的解决方案。

如果我没有说清楚,请告诉我。否则,非常感谢您的及时帮助!!

Power Query 和 Power BI 是两种不同的工具。

Power Query 旨在处理数据。它使用称为 "m" 的语言。例如,如果您需要导入和合并文件、修复错误数据等——这就是您所使用的。

Power BI 旨在分析数据。它使用称为 "DAX" 的语言。大多数时候,Power BI/DAX 可用于设计交互式分析 - 响应切片器、过滤器等的报告。

一些人使用 DAX 而不是 Power Query 来增强他们的数据——比如添加计算列。就个人而言,我认为这是个坏主意,但也许 Power Query/m 对他们来说太 non-intuitive 而 DAX 更容易。我将解释如何使用 DAX 添加计算列。如果出于某种原因您更喜欢 Power Query,请在您的问题中提及。

首先,您必须在主 Power BI window 中,而不是在 Power Query window 中。转到您的数据模型,然后 select 您的 table。在选项卡 "model" 上,单击 "add column"。输入 DAX 公式:

Last Date = 
  VAR Current_Date = Table1[Date]
  VAR Current_Name = Table1[Name]
RETURN
  CALCULATE( MAX(Table1[Date]), 
             Table1[Date] < Current_Date,
             Table1[Name] = Current_Name )

该公式将为每个名称生成一个包含之前日期的新列。

工作原理:

  • 计算列时,Power BI 逐条迭代table条记录。对于每条记录,我们将其日期存储在变量 "Current_Date" 中,并将其名称存储在 "Current_Name";
  • 然后,我们需要找到一个日期:a) 小于 current_date,并且 b) 仅针对当前名称。这是通过使用 2 个过滤器计算 MAX 日期来完成的:日期必须 < 然后 Current_Date,名称必须 = Current_Name.

例如,对于name "B",首先突出显示:它将首先过滤table,只留下name = "B" 的记录(3 条记录)。然后,它会进一步过滤这3条记录,找到dates < 11/08/2019,即一条记录:5/07/2019.

附带说明一下,我建议至少阅读一本关于 Power 的好书 BI/DAX,或参加在线培训 class。这个工具并不简单,如果你试图通过反复试验来学习它,你会浪费很多时间。

在RADO的指引下,我用M语言和built-in GUI搜索了几个类似的Power Query案例,我找到了解决问题的方法。

1) 首先按以下顺序对我的 table 进行升序排序:姓名、日期;

2) 添加两个索引列,一个以0开头,一个以1开头,然后合并table自身匹配的索引列0和索引列1;

3) 展开合并列 [Name.1] 和 [Date.1],然后使用以下 if 函数添加名为 "Last Date" 的自定义列

if [Name]=[Name.1] then [Date.1] else null

4) 删除其他列,仅保留 [Name]、[Date] 和 [Last Date] 列。

如果我有几个 table 需要相同的操作,上述方法有点乏味。如果有人可以使用可应用于其他 table 的单个查询提供 'Custom Function' 解决方案,我们将不胜感激!

自定义函数可能类似于:

let
    AddLastDateColumn = (someTable as table) as table =>
        let
            initialHeaders = Table.ColumnNames(someTable),
            sorted = Table.Sort(someTable, {{"Date", Order.Ascending}, {"Name", Order.Ascending}}),
            merged = Table.NestedJoin(sorted, {"Name"}, sorted, {"Name"}, "$joined", JoinKind.LeftOuter),
            lastDateColumn = Table.AddColumn(merged, "Last Date", each
                let
                    maxDate = [Date],
                    filtered = Table.SelectRows([#"$joined"], each [Date] < maxDate),
                    lastRow = if not Table.IsEmpty(filtered) then Table.Last(filtered)[Date] else null // Could use Table.Max, but data is already sorted.
                in lastRow,
                type nullable date),
            dropColumns = Table.SelectColumns(lastDateColumn, initialHeaders & {"Last Date"})
        in dropColumns
in
    AddLastDateColumn

如果将以上内容保存为自己的查询,则可以在其他查​​询中访问它。例如,如果将上面的内容保存为名为 AddLastDateColumn 的查询,则可以访问 它在其他查询中(如下所示):

let
    sourceTable =
        let
            nameColumn = {"A", "B", "C", "D", "E", "F", "G", "A", "B", "C", "D", "E", "F", "G", "A", "B", "C", "D", "E", "F", "G"},
            dateColumn = {#date(2019,7,1), #date(2019,7,5), #date(2019,7,14), #date(2019,7,23), #date(2019,7,24), #date(2019,8,1), #date(2019,8,5), #date(2019,8,10), #date(2019,8,11), #date(2019,8,17), #date(2019,8,23), #date(2019,8,25), #date(2019,9,3), #date(2019,9,4), #date(2019,9,13), #date(2019,9,17), #date(2019,9,23), #date(2019,9,27), #date(2019,9,28), #date(2019,10,6), #date(2019,10,9)},
            toTable = Table.FromColumns({nameColumn, dateColumn}, type table [Name = text, Date = date])
        in toTable,
    invokeFunction = AddLastDateColumn(sourceTable)
in
    invokeFunction

我正在查看 Table.NestedJoin (https://docs.microsoft.com/en-us/powerquery-m/table-nestedjoin) 的文档。它似乎有一个名为 keyEqualityComparers:

的参数

An optional set of keyEqualityComparers may be included to specify how to compare the key columns.

我没有时间研究它的功能和它需要的语法,但也许它可以用来更优雅地指定 JOIN 条件:"Name 必须完全匹配. Right Date 必须是小于 Left Date".

的最大日期

无论如何,我认为上面的函数应该可以满足您的需求。