将带有标志的行中的数字滚动到没有标志的下一行

时间:2013-09-25 15:00:59

标签: sql-server subquery aggregate-functions

我对如何解决我正在处理的这个特定问题感到有点难过。我从一个更大的问题开始,但我设法将其简化为此,同时保持良好的性能。

说我有以下结果集。 AggregateMe是我从SQL条件派生的东西。

MinutesElapsed   AggregateMe    ID    Type   RowNumber
1480             1              1     A      1
1200             0              1     A      2
1300             0              1     B      3
1550             0              1     C      4
725              1              1     A      5
700              0              1     A      6
1900             1              2     A      7
3300             1              2     A      8
4900             0              2     A      9

如果AggregateMe为1(true),或者如果您愿意,如果为true,我希望将计数聚合到AggregateMe(或条件)未评估为true的下一行。 聚合函数或子查询是公平游戏,就像PARTITION BY一样。

例如,上述结果集将变为:

MinutesElapsed     ID   Type
2680               1    A       
1300               1    B       
1550               1    C       
1425               1    A       
10100              2    A       

有干净的方法吗?如果你愿意,我可以分享更多有关原始问题的信息,但它有点复杂。

编辑添加:SUM和GROUP BY单独工作,因为一些总和将被卷入错误的行。我的示例数据没有反映出这种情况,因此我添加了可以发生此情况的行。在更新的样本数据中,以最简单的方式使用聚合函数会导致2680计数和1425计数一起滚动,这是我不想要的。

编辑:如果你想知道我是怎么来到这里的,那你就去吧。我将汇总有关程序在某个ActionType中保留多长时间的统计信息,我的第一步是创建此子查询。请随意批评:

select 
    ROW_NUMBER() over(order by claimid, insertdate asc) as RowNbr,
    DateDiff(mi, ahCurrent.InsertDate, CASE WHEN ahNext.NextInsertDate is null THEN GetDate() ELSE ahNext.NextInsertDate END) as MinutesInActionType,
    ahCurrent.InsertDate, ahNext.NextInsertDate,
    ahCurrent.ClaimID, ahCurrent.ActionTypeID,
    case when ahCurrent.ActionTypeID = ahNext.NextActionTypeID and ahCurrent.ClaimID = ahNext.NextClaimID then 1 else 0 end as aggregateme
    FROM 
    (
        select ROW_NUMBER () over(order by claimid, insertdate asc) as RowNum, ClaimID, InsertDate, ActionTypeID
        From autostatushistory
        --Where AHCurrent is not AHPast
    ) ahCurrent
    LEFT JOIN
    (
        select ROW_NUMBER() over(order by claimid, insertdate asc) as RowNum, ClaimID as NextClaimID, InsertDate as NextInsertDate, ActionTypeID as NextActionTypeID
        FROM autostatushistory
    ) ahNext 
    ON (ahCurrent.ClaimID = ahNext.NextClaimID AND ahCurrent.RowNum = ahNext.RowNum - 1 and ahCurrent.ActionTypeID = ahNext.NextActionTypeID)

2 个答案:

答案 0 :(得分:1)

这里是你需要执行的查询, 它不干净,也许你会优化它:

WITH cte AS( /* Create a table containing row number */
SELECT ROW_NUMBER() OVER (ORDER BY (SELECT 1)) AS ROW,
       MinutesElapsed,
       AggregateMe,
       ID,
       TYPE
    FROM rolling
)
SELECT MinutesElapsed + (CASE          /* adding minutes from next valid records*/
                         WHEN  cte.AggregateMe <> 1   /*if current record is 0 then */
                         THEN 0                        /*skip it*/
                         ELSE  
                             (SELECT SUM(MinutesElapsed) /* calculating sum of all -> */
                             FROM cte localTbl
                             WHERE
                                  cte.ROW < localTbl.ROW /* next records -> */
                                AND
                                  localTbl.ROW <= (      /* until we find aggregate = 0 */
                                                   SELECT MIN(ROW) 
                                                   FROM cte sTbl
                                                   WHERE sTbl.AggregateMe = 0
                                                         AND
                                                         sTbl.ROW > cte.ROW
                                                   )
                                AND 
                                  (localTbl.AggregateMe = 0 OR /* just to be sure :) */
                                    localTbl.AggregateMe = 1))
                          END) as MinutesElapsed,
       AggregateMe,
       ID,
       TYPE
FROM cte
WHERE cte.ROW = 1 OR NOT(       /* not showing records used that are used in sum, skipping 1 record*/           
    (                          /* records with agregate 0 after record with aggregate 1 */
      cte.AggregateMe = 0 
      AND
      (
        SELECT AggregateMe
        FROM cte tblLocal
        WHERE cte.ROW = (tblLocal.ROW + 1)
      )>0
    ) 
  OR
     (   /* record with aggregate 1 after record with aggregate 1 */
      cte.AggregateMe = 1 
      AND
      (
        SELECT AggregateMe
        FROM cte tblLocal
        WHERE cte.ROW = (tblLocal.ROW + 1)
      )= 1
    )
);

测试here

希望它对您的问题有所帮助。 随时提问。

答案 1 :(得分:0)

通过查看您的结果集,似乎以下工作,

SELECT ID,Type,SUM(MinutesElapsed)
FROM mytable
GROUP BY ID,Type

但是如果不查看原始数据集,就无法确定。