Transact-SQL - 直到满足条件的数字行

时间:2016-09-15 18:31:56

标签: sql-server tsql count reset row-number

我正在尝试在“x”列中生成数字,考虑字段“eq”中的值,以便它应该为每个记录设置一个数字,直到它满足值“1”,然后下一个行应重置并重新开始计数。我尝试过使用row_number,但问题是我只需要在我需要评估的列中使用1和0,而我使用row_number看到的情况是在列中使用增长值。也尝试了排名,但我还没有设法让它发挥作用。

nInd    Fecha       Tipo    @Inicio     @contador_I  @Final     @contador_F eq  x
1       18/03/2002  I       18/03/2002  1            null       null        0   1
2       20/07/2002  F       18/03/2002  1            20/07/2002 1           1   2
3       19/08/2002  I       19/08/2002  2            20/07/2002 1           0   1
4       21/12/2002  F       19/08/2002  2            21/12/2002 2           1   2
5       17/03/2003  I       17/03/2003  3            21/12/2002 2           0   1
6       01/04/2003  I       17/03/2003  4            21/12/2002 2           0   2
7       07/04/2003  I       17/03/2003  5            21/12/2002 2           0   3
8       02/06/2003  F       17/03/2003  5            02/06/2003 3           0   4
9       31/07/2003  F       17/03/2003  5            31/07/2003 4           0   5
10      31/08/2003  F       17/03/2003  5            31/08/2003 5           1   6
11      01/09/2005  I       01/09/2005  6            31/08/2003 5           0   1
12      05/09/2005  I       01/09/2005  7            31/08/2003 5           0   2
13      31/12/2005  F       01/09/2005  7            31/12/2005 6           0   3
14      14/01/2006  F       01/09/2005  7            14/01/2006 7           1   4

4 个答案:

答案 0 :(得分:3)

还有另一种解决方案:

select 
  nind, eq, row_number() over (partition by s order by s) 
from (
  select 
    nind, eq, coalesce((
      select sum(eq) +1 from mytable pre where pre.nInd < mytable.nInd)
    ,1) s --this is the sum of eq!
  from mytable) g

内部子查询在groups中每次出现1时依次创建eq。然后我们可以使用row_number() over partition来获取我们的计数器。

Here is an example使用Sql Server

答案 1 :(得分:1)

我在这里有两个答案。一个基于ROW_NUMBER(),另一个基于您的索引(nInd)。我不确定你的索引是否有差距,所以我也做了ROW_NUMBER()

我的表格格式如下 -

myIndex int identity(1,1) NOT NULL number int NOT NULL

第一个是ROW_NUMBER() ...

WITH rn AS (SELECT *, ROW_NUMBER() OVER (ORDER BY myIndex) AS rn, COUNT(*) AS max 
                  FROM counting c GROUP BY c.myIndex, c.number)
,cte (myIndex, number, level, row) AS (

    SELECT r.myIndex, r.number, 1, r.rn + 1 FROM rn r WHERE r.rn = 1
    UNION ALL
    SELECT r1.myIndex, r1.number, 
                       CASE WHEN r1.number = 0 AND r2.number = 1 THEN 1
                                                                 ELSE c.level + 1
                       END,
                       row + 1
    FROM cte c 
        JOIN rn r1 
            ON c.row = r1.rn
        JOIN rn r2
            ON c.row - 1 = r2.rn
    )

SELECT c.myIndex, c.number, c.level FROM cte c OPTION (MAXRECURSION 0);

现在索引......

WITH cte (myIndex, number, level) AS (

    SELECT c.myIndex + 1, c.number, 1 FROM counting c WHERE c.myIndex = 1
    UNION ALL
    SELECT c1.myIndex + 1, c1.number, 
                           CASE WHEN c1.number = 0 AND c2.number = 1    THEN 1
                                                                        ELSE c.level + 1
                           END
    FROM cte c 
        JOIN counting c1
            ON c.myIndex = c1.myIndex
        JOIN counting c2
            ON c.myIndex - 1 = c2.myIndex
    )

SELECT c.myIndex - 1 AS myIndex, c.number, c.level FROM cte c OPTION (MAXRECURSION 0);

答案 2 :(得分:0)

我现在的答案是使用

Cursor

我知道如果有另一种没有光标的解决方案,那么性能方面会更好

这是我的解决方案的快速演示:

  -- Create DBTest
  use master
  Go
  Create Database DBTest
  Go
  use DBTest
  GO
  -- Create table
  Create table Tabletest
  (nInd    int , eq  int)
  Go
  -- insert dummy data
  insert into Tabletest (nInd,eq) 
  values    (1,0),
            (2,1),
            (3,0),
            (4,1),
            (5,0),
            (6,0),
            (7,0),
            (8,0),
            (9,1),
            (8,0),
            (9,1)



  Create table #Tabletest (nInd int ,eq int ,x int )
  go

  DECLARE  @nInd int , @eq int , @x int
  set @x = 1
  DECLARE db_cursor CURSOR FOR  
  SELECT nInd , eq
  FROM Tabletest  
  order by nInd

  OPEN db_cursor   
  FETCH NEXT FROM db_cursor INTO @nInd , @eq   

  WHILE @@FETCH_STATUS = 0   
  BEGIN   

   if (@eq = 0) 
     begin

            insert into #Tabletest (nInd ,eq  ,x) values (@nInd , @eq , @x)
            set @x = @x +1
     end 
     else if (@eq = 1)
     begin
            insert into #Tabletest (nInd ,eq  ,x) values (@nInd , @eq , @x)
            set @x = 1
     end

    FETCH NEXT FROM db_cursor INTO @nInd , @eq   

  END   

  CLOSE db_cursor   
  DEALLOCATE db_cursor


  select * from #Tabletest

最终结果集如下:

enter image description here

希望它有所帮助。

答案 3 :(得分:0)

以稍微不同的方式(可能不是这样,但不需要递归CTE的游标),看起来就像在数据集中构建有序组一样。因此,首先找到这些组,然后确定每个组的顺序。

真正的关键是确定查找更正分组的规则。根据您的说明和评论,我猜测分组是从一开始(按nInd列排序),每行结束时eq值为1,所以你可以这样做:

;with ends(nInd, ord) as (
    --Find the ending row for each set
    SELECT nInd, row_number() over(order by nInd)
    FROM mytable
    WHERE eq=1
), ranges(sInd, eInd) as (
    --Find the previous ending row for each ending row, forming a range for the group
    SELECT coalesce(s.nInd,0), e.nInd
    FROM ends s
        right join ends e on s.ord=e.ord-1
)

然后,使用这些组范围,您可以找到每个组的最终顺序:

select t.nInd, t.Fecha, t.eq
    ,[x] = row_number() over(partition by sInd order by nInd)
from ranges r
    join mytable t on r.sInd < t.nInd
                    and t.nInd <= r.eInd
order by t.nInd