SQL Server 2012:有条件地增加计数器用户ROW_NUMBER()

时间:2014-09-30 03:39:24

标签: sql sql-server row-number

我正在尝试应用ROW_NUMBER()根据特定条件递增计数器。

我的数据如下所示,目标计数器为Prep

    id       DSR    PrepIndicator   Prep
   --------------------------------------
    1662835  -1     1               1
    1662835  14     2               2
    1662835  14     2               3
    1662835  20     2               4
    1667321  -1     1               1
    1667321  30     2               2
    1667321  14     2               3
    1680648  -1     1               1
    1680648  14     2               2
    1680648  60     1               1
    1680648  14     2               2
    1680648  14     2               3
    1683870  -1     1               1
    1683870  12     2               2
    1683870  10     2               3
    1683870  60     1               1
    1683870  7      2               2

暂时忽略PrepIndicator列,我尝试实现的业务逻辑如下:

  • 对于每个Id,从1开始,如果DSR小于42,则递增Prep计数器。
  • 如果为42或更高,请将“准备”计数器重置为1.

PrepIndicator实际上会创建一个标记来实现此功能,如果PrepIndicator = 1则为Prep = 1。如果PrepIndicator = 2,则增加Prep

如果可能,我希望在没有PrepIndicator列的情况下实现此目的。

如何使用ROW_NUMBER()实现此条件增量?

我试过

ROW_NUMBER() OVER (PARTITION BY id, PrepIndicator ORDER BY id) 

DSR>= 42时似乎无效。

任何建议或帮助都会很棒。谢谢!

2 个答案:

答案 0 :(得分:0)

首先,您需要明确的订购。 "递增计数器"只有你有一个以前的值才有意义。您可以向表中添加IDENTITY列,也可以使用ROW_NUMBER() OVER ORDER BY(/* your logic here */)。在你的表中,你甚至没有前三列的唯一值(见1680648,14,2),所以我认为添加一个ID是可行的。

要做你想要达到的目标,我相信你必须在循环中做到这一点。如果您使用ROW_NUMBER(),您可能希望选择临时表。根据您的问题的性质,术语计数器表示您将拥有一个变量。

UPDATE TableA SET rowId = ROW_NUMBER() OVER(ORDER BY id, DSR, PrepIndicator)

然后"有条件的"似乎很好地利用了CASE

DECLARE @counter INT = 1
DECLARE @row INT = 1
DECLARE @DSR INT

UPDATE TableA SET Prep = @counter
SET @row = (SELECT rowId FROM TableA WHERE rowId > @row)

WHILE EXISTS( SELECT TOP 1 1 FROM TableA WHERE rowId = @row )
BEGIN
    SELECT @DSR = DSR FROM TableA WHERE rowId = @row
    SET @counter = CASE WHEN @DSR < 42 THEN @counter + 1 ELSE 1 END
    UPDATE TableA SET Prep = @counter WHERE rowId = @row
    SET @row = (SELECT rowId FROM TableA WHERE rowId > @row)
END

答案 1 :(得分:0)

首先,您需要添加主键,因为SQL表中没有物理顺序;我们可以称之为IdK。然后,以下代码应该为您提供所需内容:

select *, row_number() over (partition by Id, (Select Count (*) from MyTable t2 where t2.idk <= t1.idk and t2.id = t1.id and DSR >= 42) order by idk) prep
from MyTable t1
order by idk

至于为什么你的代码不起作用,这是因为在分区/编号完成之前首先对行进行分组。在分区的两列id和PrepIndicator的情况下,我们在编号之前的最后5行获得以下中间结果:

id       DSR    PrepIndicator   Row_Number (Id, PrepIndicator)
1683870  -1     1               1
1683870  60     1               2
1683870  12     2               1
1683870  10     2               2
1683870  7      2               3

请注意,DSR = 60的行现在位于第二个位置。这显然是你不想拥有的。在选择计数(*)...的情况下,我们在分组完成后的最后5行中得到以下结果,就在编号之前:

id       DSR    ...Count()   Row_Number (Id, ...Count())
1683870  -1     0               1
1683870  12     0               2
1683870  10     0               3
1683870  60     1               1
1683870  7      1               2

您可以注意到,在这种情况下,任何行的位置都没有变化。