在SQL Server 2008中的公用表表达式中使用分组依据

时间:2019-03-11 23:33:22

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

我试图对不同的行数据进行平均,如下所示。

这是我的原始Questions  McNets回答了。

所以基本上这是桌子

create table t (id int identity, BIDID int,  AppID int, AppStatus varchar(20), [Time] date);
insert into t values
(23390, 16, 'In Review', '20170307'), 
(23390, 16, 'Approved',  '20170309'), 
(23390, 16, 'In Review', '20171110'), 
(23390, 16, 'Approved',  '20171112'), 
(23390, 17, 'In Review',  '20171114'),
(23390, 18, 'Approved',  '20171112'), 
(23390, 16, 'Approved',  '20171114'),
(23391, 17, 'In Review',  '20171112'), 
(23391, 17, 'Approved',  '20171114')

我尝试仅首先在单个AppID之间计算In Review和Approved值之间的平均值,然后在单个出价中对不同AppId进行平均值计算,然后最后在所有出价之间求平均值以得出一个数字

这是代码

SELECT
    CASE WHEN t1.AppStatus = 'In Review' AND t2.AppStatus = 'Approved'
         THEN DATEDIFF(day, t1.[Time], t2.[Time])
         ELSE 0
    END as Days
FROM
    t t1
CROSS APPLY(SELECT TOP 1 * 
            FROM t
            WHERE id > t1.id
            ORDER BY id) t2

这让我得到了平均值

WITH ct AS
(
SELECT
    CASE WHEN t1.AppStatus = 'In Review' AND t2.AppStatus = 'Approved'
         THEN DATEDIFF(day, t1.[Time], t2.[Time])
         ELSE 0
    END as Days
FROM
    t t1
CROSS APPLY(SELECT TOP 1 * 
            FROM t
            WHERE id > t1.id
            ORDER BY id) t2
)
SELECT
    SUM(days) / COUNT(*) Average
FROM
    ct
WHERE
    days <> 0

此操作目前不进行任何形式的分组,因此仅将“审核中”考虑在内,然后查找下一个“批准”,依此类推。我需要先按AppID对其进行分组,以计算各个AppId的平均值,然后对出价内不同AppId的平均值进行平均,然后对出价的平均值进行

有人可以告诉我如何添加分组。

预期结果

    (1 23390, 16, 'In Review', '20170308'), 
    (2 23390, 16, 'Approved',  '20170309'), 
    (3 23390, 16, 'In Review', '20171110'), 
    (4 23390, 16, 'Approved',  '20171112'), 
    (5 23390, 17, 'In Review',  '20171114'),
    (6 23390, 18, 'In Review',  '20171112'), 
    (7 23390, 16, 'Approved',  '20171114'),
    (8 23391, 17, 'In Review',  '20171112'), 
    (9 23391, 17, 'Approved',  '20171114')

23390 AppID16 FirstData Id1 to Id2  1Day       (In Review -> Approved)
23390 AppID16 SecondData Id3 to Id4 2Day
23390 AppID16 ThirdData Id7 Ignored Since no In Review Before..

Avg AppID 16 = 1.5 days

23390 AppID 17 ignored since no Approved after in review
23390 AppID 18 Ignored 

Avg for 23390 = 1.5

..类似地计算其他出价的平均值

23391 AppID 17天2。

因此,两次出价之间的平均总和为2 + 1.5 / 2

DBFiddle

谢谢

1 个答案:

答案 0 :(得分:1)

这是一种方法。非常简单。每个步骤都包裹在CTE中。检查每个CTE的中间结果,以了解其工作原理并查看代码中的注释。

样本数据

create table t (id int identity, BIDID int,  AppID int, AppStatus varchar(20), dt date);
insert into t values
(23390, 16, 'In Review', '20170308'), 
(23390, 16, 'Approved',  '20170309'), 
(23390, 16, 'In Review', '20171110'), 
(23390, 16, 'Approved',  '20171112'), 
(23390, 17, 'In Review',  '20171114'),
(23390, 18, 'Approved',  '20171112'), 
(23390, 16, 'Approved',  '20171114'),
(23391, 17, 'In Review',  '20171112'), 
(23391, 17, 'Approved',  '20171114');

查询

我调整了您的CROSS APPLY,使其与问题中描述的逻辑相符。

WITH
-- Find matching pairs and calculate the difference of individual dates
CTE_Diffs
AS
(
    SELECT
        MainT.id
        ,MainT.BIDID
        ,MainT.AppID
        ,CAST(DATEDIFF(day, MainT.dt, NextT.dt) AS float) AS Diff
    FROM
        T AS MainT
        CROSS APPLY
        (
            SELECT TOP 1 
                T.AppStatus
                ,T.dt
            FROM T
            WHERE
                -- the matching row must be from the same Bid and App
                -- and have a higher ID
                T.BIDID = MainT.BIDID
                AND T.AppID = MainT.AppID
                AND T.id > MainT.id
            ORDER BY
                T.id
        ) AS NextT
    WHERE
        -- the pair is counted only when it starts with 'In Review' and finishes with 'Approved' 
        MainT.AppStatus = 'In Review'
        AND NextT.AppStatus = 'Approved'
)
-- Average by Bid and App
,CTE_AvgBidApp
AS
(
    SELECT
        BIDID
        ,AppID
        ,AVG(Diff) AS AvgBidApp
    FROM CTE_Diffs
    GROUP BY
        BIDID
        ,AppID
)
-- Average by Bid
,CTE_AvgBid
AS
(
    SELECT
        BIDID
        ,AVG(AvgBidApp) AS AvgBid
    FROM CTE_AvgBidApp
    GROUP BY
        BIDID
)
-- Final average
SELECT
    AVG(AvgBid) AS TotalAvg
FROM CTE_AvgBid
;

结果

TotalAvg
1.75

清理

DROP TABLE t;