简体   繁体   English

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

[英]SQL Server 2012: Conditionally Incrementing a counter user ROW_NUMBER()

I am trying to apply ROW_NUMBER() to increment a counter based on particular conditions. 我正在尝试应用ROW_NUMBER()来根据特定条件递增计数器。

My data looks like this, with the target counter being the Prep column 我的数据看起来像这样,目标计数器是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

Ignoring the PrepIndicator column for the moment, the business logic I am trying to implement is as follows: PrepIndicator忽略PrepIndicator列,我试图实现的业务逻辑如下:

  • For each of the Id's, starting from 1, increment the Prep counter if the DSR is less than 42. 对于每个Id,从1开始,如果DSR小于42,则递增Prep计数器。
  • If it is 42 or greater, reset the Prep counter to 1. 如果为42或更高,请将Prep计数器重置为1。

The PrepIndicator , in effect, creates a flag to implement this, in that if PrepIndicator = 1 then Prep = 1 . 实际上, PrepIndicator会创建一个标志来实现它,如果PrepIndicator = 1Prep = 1 If PrepIndicator = 2 , then increment Prep . 如果PrepIndicator = 2 ,则增加Prep

I'd prefer to achieve this without the PrepIndicator column if possible. 如果可能的话,我更愿意在没有PrepIndicator专栏的情况下实现这一PrepIndicator

How would I achieve this conditional increment with ROW_NUMBER() ? 如何使用ROW_NUMBER()实现此条件增量?

I've tried 我试过了

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

but it doesn't seem to work when the DSR is >= 42 . 但是当DSR >= 42时它似乎不起作用。

Any suggestions or help would be great. 任何建议或帮助都会很棒。 Thanks! 谢谢!

First, you will need explicit ordering. 首先,您需要明确的订购。 "Incrementing the counter" only has meaning if you have a previous value. 如果你有一个以前的值,“递增计数器”只有意义。 You can add an IDENTITY column to the table, or use ROW_NUMBER() OVER ORDER BY(/* your logic here */) . 您可以向表中添加IDENTITY列,或使用ROW_NUMBER() OVER ORDER BY(/* your logic here */) In your table, you do not even have unique values for the first three columns (see 1680648, 14, 2), so I would think adding an ID is the way to go. 在您的表中,您甚至没有前三列的唯一值(请参阅1680648,14,2),因此我认为添加ID是可行的方法。

To do what you want to achieve, I believe you must do this in a loop. 为了做你想要达到的目标,我相信你必须在循环中做到这一点。 If you use ROW_NUMBER() you may wish to select into a temporary table. 如果您使用ROW_NUMBER()您可能希望选择一个临时表。 By the nature of your question, the term counter indicates you will have a variable. 根据您的问题的性质,术语计数器表示您将拥有一个变量。

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

then "conditional" seems to signal a good use of CASE 然后“有条件的”似乎表明了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

First, you need to add a primary key because there is no physical order in a SQL table; 首先,您需要添加主键,因为SQL表中没有物理顺序; we can call it IdK. 我们可以称之为IdK。 The following code should then give you what you want: 然后,以下代码应该为您提供所需内容:

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

As to why your code doesn't work, this is because the rows are first grouped before the partition/numbering is done. 至于为什么你的代码不起作用,这是因为在分区/编号完成之前首先对行进行分组。 In the case with the two columns id and PrepIndicator for the partition, we get the following intermediary result for the last 5 row before the numbering: 在分区的两列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

Notice that the line with DSR = 60 is now in the second position. 请注意,DSR = 60的行现在位于第二个位置。 This is clearly what you don't want to have. 这显然是你不想拥有的。 In the case with the Select count(*)..., we have the following result for the last 5 rows after the grouping is done, just before the numbering: 在Select count(*)...的情况下,我们在分组完成后的最后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

You can notice that in this case, there is no change of position for any row. 您可以注意到,在这种情况下,任何行的位置都没有变化。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM