如何在增量值重新开始时排除行?

时间:2015-11-19 18:45:56

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

我是一张新手海报,但是花了很多时间在这里研究答案。我无法弄清楚如何使用SQL Server 2008 R2创建一个SQL结果集,该结果集应该使用更现代版本的超前/滞后。我试图根据一列的序列聚合数据,但每个序列中可能有不同数量的实例。我知道序列已经结束的唯一方法是下一行的序列号较低。所以它可能会出现1-2,1-2-3-4,1-2-3,我必须弄清楚如何制作3个聚合。

源数据是连接的表,看起来像这样(请帮我格式化):

recordID instanceDate moduleID iResult interactionNum
1356    10/6/15 16:14   1        68          1
1357    10/7/15 16:22   1        100         2
1434    10/9/15 16:58   1        52          1
1435    10/11/15 17:00  1        60          2
1436    10/15/15 16:57  1        100         3
1437    10/15/15 16:59  1        100         4

我需要找到一种方法,根据最后一列中的值,将前两行与最后4行分开。

我最想得到的是一个看起来像这样的结果集,它根据分组对iResult列进行平均,并从分组中获取第一个instanceDate:

instanceDate    moduleID    iResult
10/6/15           1          84
10/9/15           1          78

如果我能找到一种分离组的方法,我可以使用MIN和AVG进行聚合以获得此结果。数据按instanceDate排序(请忽略此处的日期格式)然后当查询找到interactionNum为< =而不是前一行的行时(通常会以' 1& #39;但并非总是如此,所以最好只是在较低或相等的整数值上分开。)

这是我到目前为止的查询(包括提供上述数据集的连接):

SELECT 
    X.* 
FROM
   (SELECT TOP 100 PERCENT   
        instanceDate, b.ModuleID, iResult, b.interactionNum 
    FROM 
        (firstTable a  
    INNER JOIN 
        secondTable b ON b.someID = a.someID)       
    WHERE 
        a.someID = 2        
        AND b.otherID LIKE 'xyz'    
        AND a.ModuleID = 1
    ORDER BY 
        instanceDate) AS  X

OUTER APPLY

(SELECT TOP 1 
     *
 FROM
     (SELECT    
          instanceDate, d.ModuleID, iResult, d.interactionNum   
      FROM 
          (firstTable c  
      INNER JOIN 
          secondTable d ON d.someID = c.someID) 
      WHERE 
          c.someID = 2      
          AND d.otherID LIKE 'xyz'  
          AND c.ModuleID = 1    
          AND d.interactionNum = X.interactionNum
          AND c.instanceDate < X.instanceDate)  X2
      ORDER BY 
          instanceDate DESC) Y
WHERE 
    NOT EXISTS (SELECT Y.interactionNum INTERSECT SELECT X.interactionNum)

但是这会返回一个像这样的中间结果集:

instanceDate    ModuleID    iResult interactionNum
10/6/15 16:10   1            68         1
10/6/15 16:14   1            100        2
10/15/15 16:57  1            100        3
10/15/15 16:59  1            100        4

问题是interactionNum 3,4不属于此结果集。当我遍历此查询时,它们将进入下一个结果集。如何在这次迭代中将它们排除在结果集之外?我需要此查询的结果集才能包含前两行,&#39;看到&#39;第3行的源数据具有较低的interactionNum值而不是第2行具有的值。

2 个答案:

答案 0 :(得分:5)

不确定应该使用什么ModuleID,但我想你正在寻找这样的东西:

select min (instanceDate), [moduleID], avg([iResult])
from (
  select *,row_number() over (partition by [moduleID] order by instanceDate) as RN
  from Table1
) X
group by [moduleID], RN - [interactionNum]

这里的想法是为每个moduleid创建一个带有row_number的运行编号,然后使用它与InteractionNum之间的差异作为分组标准。

SQL Fiddle

中的示例

答案 1 :(得分:0)

这是我的解决方案,虽然应该说,但我认为@JamesZ答案更清晰。

我创建了一个名为newinstance的新字段,只要您的instanceNumber为1,就会为1.我创建了一个名为sum(newinstance)的滚动rollinginstance来分组。

将上次选择更改为SELECT * FROM cte2以显示我添加的所有字段。

IF OBJECT_ID('tempdb..#tmpData') IS NOT NULL
    DROP TABLE #tmpData

CREATE TABLE #tmpData (recordID INT, instanceDate DATETIME, moduleID INT, iResult INT, interactionNum INT)

INSERT INTO #tmpData
SELECT 1356,'10/6/15 16:14',1,68,1 UNION
SELECT 1357,'10/7/15 16:22',1,100,2 UNION
SELECT 1434,'10/9/15 16:58',1,52,1 UNION
SELECT 1435,'10/11/15 17:00',1,60,2 UNION
SELECT 1436,'10/15/15 16:57',1,100,3 UNION
SELECT 1437,'10/15/15 16:59',1,100,4

;WITH cte1 AS
(
    SELECT *,
           CASE WHEN interactionNum=1 THEN 1 ELSE 0 END AS newinstance,
           ROW_NUMBER() OVER(ORDER BY recordID) as rowid
    FROM #tmpData
), cte2 AS
    (
        SELECT *,
               (select SUM(newinstance) from cte1 b where b.rowid<=a.rowid) as rollinginstance
        FROM cte1 a
    )

SELECT MIN(instanceDate) AS instanceDate, moduleID, AVG(iResult) AS iResult
FROM cte2
GROUP BY moduleID, rollinginstance