如何在SQL中按连续值分组

时间:2016-08-29 20:49:23

标签: sql-server tsql

我在SQL Server 2014中有一个表,其中的示例数据如下所示。

WK_NUM | NET_SPRD_LCL 
10       0 
11       1500 
12       3600 
13       3800 
14       4000

我正在尝试在工作中编写奖金结构,我需要在WK_NUM上进行分组。所以,如果我看到NET_SPRD_LCL> 3500表示两个连续的WK_NUMs WHERE WK_NUM< 27,我需要输出2000.在这个例子中,由于WK_NUM 12和13的NET_SPRD_LCL都大于3500,所以SQL应输出2000并退出。因此,它应该忽略WK_NUM 13和14也满足NET_SPRD_LCL>的条件的事实。 3500。

我很感激任何帮助。

2 个答案:

答案 0 :(得分:2)

假设你的意思是连续的第1,2,3,4,5 ......等等而不是 1,3,5,8,12等

然后,如果您不需要知道它是哪一对连续记录:

Select case when exists
   (Select * from table f
       join table n
          on n.Wk_Num = f.Wk_Num + 1
             and n.NET_SPRD_LCL > 3500
             and f.NET_SPRD_LCL > 3500
             and n.Wk_Num < 27
    then 2000 else null end

如果您确实需要识别这对记录,那么:

Select f.wk_Num firstWorkNbr, f.NET_SPRD_LCL firstNetSpread,
       n.wk_Num nextWorkNbr, n.NET_SPRD_LCL nextNetSpread
from table f
   join table n
       on n.Wk_Num = f.Wk_Num + 1
         and n.NET_SPRD_LCL > 3500
         and f.NET_SPRD_LCL > 3500
          and n.Wk_Num < 27
 Where not exists 
    (Select * from table f0
       join table n0 
           on n0.Wk_Num = f0.wk_Num + 1
              and n0.WkNum < f.Wk_Num))
另一方面,如果连续只是增加,那么它会有点困难。您需要使用子查询来确定下一个连续记录...

Select case when exists
   (Select * from table f
       join table n
          on n.Wk_Num = (Select Min(Wk_Num) from table
                         Where Wk_Num > f.Wk_Num)
             and n.NET_SPRD_LCL > 3500
             and f.NET_SPRD_LCL > 3500
             and n.Wk_Num < 27
    then 2000 else null end

如果您需要获取符合条件的特定第一对记录的数据(最后的2000是不必要的,因为如果没有合格的对,则不会返回任何内容。)

Select f.wk_Num firstWorkNbr, f.NET_SPRD_LCL firstNetSpread,
       n.wk_Num nextWorkNbr, n.NET_SPRD_LCL nextNetSpread, 2000 outValue
from table f
   join table n
       on n.Wk_Num = (Select Min(Wk_Num) from table
                      Where Wk_Num > f.Wk_Num)
         and n.NET_SPRD_LCL > 3500
         and f.NET_SPRD_LCL > 3500
          and n.Wk_Num < 27
 Where not exists 
    (Select * from table f0
       join table n0 
           on n0.Wk_Num = (Select Min(Wk_Num) from table
                           Where Wk_Num > f0.Wk_Num)
              and n0.WkNum < f.Wk_Num))

答案 1 :(得分:1)

首先,当你说你想要你的查询输出&#39;并且&#39;退出&#39;,它让我觉得你正在接近t-sql作为一种程序性语言,但事实并非如此。好的t-sql查询几乎总是基于。

在任何情况下,在查询之前,让我添加有助于其他人处理数据以构建查询的内容:

DECLARE @t TABLE (WK_NUM INT, NET_SPRD_LCL INT);
INSERT INTO @t VALUES 
(10, 0),
(11, 1500),
(12, 3600),
(13, 3800),
(14, 4000);

您说您正在使用SQL Server 2014,这意味着您可以使用相关的窗口功能。我正在使用的那个(LAG)将具有优于使用子查询的性能,如果你坚持使用它,可以通过使用带有ORDER BY的TOP(1)和适当的索引而不是整体使用MIN函数来大大改进数据集。使用少量数据,您不会注意到差异,但在实际业务系统中,这一点很明显。

调整后,在OP澄清后,在正确的行上提供2000奖金:

WITH cteTemp AS
    (
    SELECT  WK_NUM
        ,   thisValue = NET_SPRD_LCL
        ,   lastValue = LAG(NET_SPRD_LCL) OVER(ORDER BY WK_NUM)
    FROM @t
    WHERE WK_NUM < 27
    )
, cteBonusWeek AS
    (
    SELECT  TOP (1)
            WK_NUM
        ,   bonus = 2000
    FROM cteTemp
    WHERE thisValue > 3500 AND lastValue > 3500
    ORDER BY WK_NUM
    )
SELECT  t.WK_NUM
    ,   t.NET_SPRD_LCL
    ,   bonus = COALESCE(b.bonus, 0)
FROM @t AS t
LEFT JOIN cteBonusWeek AS b
    ON b.WK_NUM = t.WK_NUM;