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
".
的最大日期
无论如何,我认为上面的函数应该可以满足您的需求。
我有一个名为 '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
".
无论如何,我认为上面的函数应该可以满足您的需求。