交叉应用日期表到一些数据 - 为什么重复

时间:2013-10-28 13:25:26

标签: sql sql-server sql-server-2008-r2

这是数据:

SELECT X.*
INTO   #X
FROM   (
       VALUES
       ('A',CAST('01 Feb 2013' AS DATETIME)),
       ('B','01 Mar 2013'),
       ('C','01 Sep 2013')
       ) X(Player,Mth)

我们的仓库里有一个非常标准的工厂DimDate表。

如果我执行以下操作以查找工作正常的天数:

SELECT Player,Mth,
    numDays_mth = COUNT(XXX.DateKey),
FROM #X A
    CROSS APPLY 
    (
    SELECT DateKey 
    FROM WHData.dbo.vw_DimDate DT 
    WHERE DT.DayMarker >= A.Mth 
        AND DT.DayMarker < DATEADD(MONTH, 1, A.Mth)
    ) XXX

同样,从上个月开始的工作天数很好:

SELECT Player,Mth,
    numDays_prevMth = COUNT(YYY.DateKey)     
FROM #X A
    CROSS APPLY 
    (
    SELECT DateKey 
    FROM WHData.dbo.vw_DimDate DTT 
    WHERE DTT.DayMarker >= DATEADD(MONTH, -1, A.Mth) 
    AND DTT.DayMarker < A.Mth
    ) YYY

如果我把两者结合起来就会出现问题:

SELECT Player,Mth,
    numDays_mth = COUNT(XXX.DateKey),
    numDays_prevMth = COUNT(YYY.DateKey)    
FROM #X A
     CROSS APPLY 
     (
     SELECT DateKey 
     FROM WHData.dbo.vw_DimDate DT 
     WHERE DT.DayMarker >= A.Mth 
         AND DT.DayMarker < DATEADD(MONTH, 1, A.Mth)
     ) XXX
    CROSS APPLY 
    (
    SELECT DateKey 
    FROM WHData.dbo.vw_DimDate DTT 
    WHERE DTT.DayMarker >= DATEADD(MONTH, -1, A.Mth) 
    AND DTT.DayMarker < A.Mth
    ) YYY

我意识到还有很多其他方法可以实现这些日计算,但我正在努力了解APPLY运算符的运作方式。

如何继续使用APPLY两次并停止重复数据?


注意

SELECT子句更改为以下内容可以解决这个简单的示例,但会对生产脚本的性能产生巨大影响:

SELECT Player,Mth,
    numDays_mth = COUNT(DISTINCT XXX.DateKey),
    numDays_prevMth = COUNT(DISTINCT YYY.DateKey)   

1 个答案:

答案 0 :(得分:2)

我会移动COUNT内的CROSS APPLY,以便每个只为left hand side上的每个输入行生成一行输出。这样您就可以避免创建其他行来充当第二个(或后续)APPLY的输入:

SELECT Player,Mth,
    numDays_mth = XXX.Cnt,
    numDays_prevMth = YYY.Cnt   
FROM #X A
     CROSS APPLY 
     (
     SELECT COUNT(DateKey) 
     FROM WHData.dbo.vw_DimDate DT 
     WHERE DT.DayMarker >= A.Mth 
         AND DT.DayMarker < DATEADD(MONTH, 1, A.Mth)
     ) XXX (Cnt)
    CROSS APPLY 
    (
    SELECT COUNT(DateKey)
    FROM WHData.dbo.vw_DimDate DTT 
    WHERE DTT.DayMarker >= DATEADD(MONTH, -1, A.Mth) 
    AND DTT.DayMarker < A.Mth
    ) YYY (Cnt)