【问题标题】:DAX average not in date periodDAX 平均值不在日期期间
【发布时间】:2021-03-30 11:17:37
【问题描述】:

此 SQL 的等效 DAX 是什么?

SELECT AVG(CountRows) FROM pbi.FactVend AS FV JOIN pbi.DimAsset AS DA ON DA.KEY_Asset = FV.KEY_Asset WHERE CAST(FV.KEY_VendDate AS Date) NOT BETWEEN DA.ExcludedFromDate AND DA.ExcludedToDate

我有两张桌子,Vend 和 Asset。我想从 Vend 中排除 VendDate 处于排除期间的行。如下所示,但我无法正确使用 DAX。如果我过滤 Vend 它看不到资产列似乎也不喜欢提供转换日期,KEY_VendDate 是 Int YYYYMMDD...

Average Cup Vends = 
CALCULATE(AVERAGE(Vend[CountRows]), 
FILTER(Vend, NOT(DATESBETWEEN(CONVERT(Vend[KEY_VendDate], DATETIME), Asset[Excluded From Date], Asset[Excluded To Date])))

【问题讨论】:

  • 有人可以帮我解决这个问题吗?

标签: sql-server powerbi dax


【解决方案1】:

我不明白但我假设的事情:

  1. Assets[ProductKey] 具有唯一值。

  1. Vends(从现在起我将其称为 Transactions)包含一列 与资产相关[ProductKey]
  2. Transactions[Date] 是一个日期/时间列

  1. Transactions 与 Dates 表相关,而 Dates 表与 资产。

我不知道您是如何尝试使用测量的,但我希望以下示例可以帮助您找到正确的路径。

我只在 1 月份排除了 Assets[ProductKey],如您在 assets 表图像中所见,即:

  • Assets[ProductKey]=21 已从 2021 年 1 月 21 日 00:00 到 2021 年 1 月 22 日排除 00:00,
  • Assets[ProductKey]=22 被排除在 2021 年 1 月 22 日 00:00 至
    1/23/2021 00:00 等

您可以通过 RELATED 访问展开的 Transactions 表中的列。

FILTER(Transactions,
NOT(AND(
    Transactions[TransactionDate]>=RELATED(Assets[ExcludedFromDate]),
    Transactions[TransactionDate]<RELATED(Assets[ExcludedToDate]))))

在我的例子中。我用这个:

AVGNonExcludedTransactions := 
VAR SMZDateContext=SUMMARIZE(CalendarDateTime,CalendarDateTime[Year],CalendarDateTime[MonthName])
VAR NonExcludedTransactions= 
FILTER(Transactions,
NOT(AND(
    Transactions[TransactionDate]>=RELATED(Assets[ExcludedFromDate]),
    Transactions[TransactionDate]<RELATED(Assets[ExcludedToDate]))))
VAR Result=
ADDCOLUMNS(SMZDateContext, "Count", CALCULATE(COUNTROWS(INTERSECT(
Transactions, NonExcludedTransactions))))
RETURN
AVERAGEX(Result,[Count])

...删除突出显示的行。 Assets 表中的每个 [ProductKey] 被排除一天,而 Transactions 表中的每个产品被排除一天以上。

可以通过将 INTERSECT() 更改为 EXCEPT() 并在日级别增加粒度来进行分析。

编辑:

在第二部分中,目标不是在 Transactions 表上使用 FILTER。但是,我认为可以通过将日期更改为数字来改进以下方法。而且我仍然不知道它是否比在 10M 行表上使用 FILTER 更有效。可能不会,因为需要少于 100 种产品和超过 200 万笔交易

这是模型的样子:

这次 TCountR 是一个更简单的度量:

TCountR = COUNTROWS(Transactions)

并且过滤器是用另一种方式计算的。使用单个 DateTime 列,其中包含 CalendarDateTime 粒度内每个产品的排除期:

AVGTCountRNonExcluded := 
VAR TotalRow = 
SUMMARIZE(CalendarDateTime,CalendarDateTime[Year],CalendarDateTime[MonthName])
VAR AllCJ =
CROSSJOIN(SUMMARIZE(Products,Products[ProductKey]),SUMMARIZE(CalendarDateTime,CalendarDateTime[DateTime]))
VAR Excluded=
SELECTCOLUMNS(
    GENERATE(Assets,
                    ADDCOLUMNS(
                                CROSSJOIN (
                        //Dates in Transactions should be rounded down at the hour level.
                        // -1 means that the day 1/2/2021 is not included
                        //From 1/1/2021 00:00 to 1/1/2021 23:00
                        ////
                        //Without adding or subtracting a value:
                        //From 1/1/2021 00:00 to 1/2/2021 23:00
                                            CALENDAR(Assets[ExcludedFromDate],Assets[ExcludedToDate]-1),
                                            SELECTCOLUMNS(GENERATESERIES(0,23,1),"Time",TIME([Value],0,0))),
                                "DateTime", [Date] + [Time])),
"ProductKey", Assets[ProductKey], "DateTime", [DateTime])
VAR FilteredOut=EXCEPT(AllCJ,Excluded)
VAR Result = ADDCOLUMNS(TotalRow,"Count", CALCULATE([TCountR],KEEPFILTERS(FilteredOut)))
RETURN
AVERAGEX(Result,[Count])

结果是一样的。

编辑 2

为什么不呢?

如果您已经了解第二种方法,您可能想知道,如果我可以在我的 Transactions 表中添加一列并将 [TransactionDate] 格式从 DateTime 更改为 Date,并仅在 Date 级别使用 Dates 表,该怎么办。 示例:

1/1/2021 23:00 To 1/1/2021 00:00
1/2/2021 00:00 To 1/2/2021 00:00

代码变得更简单了:

AVGCountRowsDateLevel := 
VAR TotalRow= SUMMARIZE(Dates,Dates[Year],Dates[MonthName])
VAR AllCJ=CROSSJOIN(SUMMARIZE(Products,Products[ProductKey]),SUMMARIZE(Dates,Dates[Date]))
VAR Excluded=
SELECTCOLUMNS(
    GENERATE(Assets,
    DATESBETWEEN(Dates[Date],Assets[ExcludedFromDate],Assets[ExcludedToDate]-1)),
"ProductKey", Assets[ProductKey], "Date", [Date])
VAR FilteredOut=EXCEPT(AllCJ,Excluded)
VAR Result = ADDCOLUMNS(TotalRow,"Count", CALCULATE([TCountR],KEEPFILTERS(FilteredOut)))
RETURN
AVERAGEX(Result,[Count])

结果是一样的

正如我一开始所说,这是一个例子,希望能帮助你找到解决方案。

【讨论】:

  • 我缺少的是资产字段的相关关键字,我没有意识到我必须使用它来为相关表添加每一列,以为 DAX 会有更聪明的方法这样做......
  • DAX 不允许您通过多个列(每个产品的日期 1 到日期 2 之间)的表之间的直接关系,因为单个产品可以有多个排除日期,一个排除日期可以有多个产品在同一天。
  • 使用 FILTER+RELATED 您正在访问扩展的 Transactions 表,该表包括关系一侧的表,并将整个结果表作为表过滤器返回。使用第三种方法,您可以创建一个组合产品和日期的排除条件的表,同时利用与事务有物理关系的表的数据沿袭。
【解决方案2】:

假设你有一个从Assets[KEY_Asset]Vend[KEY_Asset] 的关系并且Vend[VendDate] 被格式化为日期,那么你可以写

Average Cup Vends =
CALCULATE (
    AVERAGE ( Vend[CountRows] ),
    FILTER (
        Vend,
        NOT AND (
            Vend[VendDate] > RELATED ( Asset[Excluded From Date] ),
            Vend[VendDate] < RELATED ( Asset[Excluded To Date] )
        )
    )
)

这需要首先定义一个计算列 Vend[VendDate] 以将 Vend[KEY_VendDate] 从 YYYYMMDD 转换为日期格式。您可以按如下方式定义这样的列:

VendDate =
DATE (
    LEFT  ( Vend[KEY_VendDate], 4 ),
    MID   ( Vend[KEY_VendDate], 5, 2 ),
    RIGHT ( Vend[KEY_VendDate], 2 )
)

另一种选择是将Asset 日期列转换为整数格式。

Average Cup Vends =
CALCULATE (
    AVERAGE ( Vend[Countrows] ),
    FILTER (
        Vend,
        NOT AND (
            Vend[KEY_VendDate]
              > VALUE ( FORMAT ( RELATED ( Asset[Excluded From Date] ), "yyyymmdd" ) ),
            Vend[KEY_VendDate]
              < VALUE ( FORMAT ( RELATED ( Asset[Excluded To Date] ), "yyyymmdd" ) )
        )
    )
)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-07-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-25
    • 2017-03-10
    • 1970-01-01
    相关资源
    最近更新 更多