2016-09-15 60 views
5

我试图在“x”列中考虑字段“eq”中的值生成数字,方式是它应该为每个记录分配一个数字,直到它遇到值“1”,下一行应重置并重新开始计数。我已经尝试过使用row_number,但问题是我需要评估的列中只有一个和零,而使用row_number看到的情况是在列中使用增长值。也尝试与排名,但我没有设法使其工作。Transact-SQL - 直到条件满足为止的行数

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 
+0

除非增加价值,你的问题很可能你不应该返回在编辑的东西已被删除。你会发现打字的东西,如“美好的一天!”和“我真的很感谢任何帮助”将被放在眼里。它只是提供额外的阅读并从实际问题中拿走。 – CodyMR

+0

感谢您的建议。我编辑它,因为第一次我把图像,但保存时没有出现。我想这是一个浏览器问题。所以我把它放在文字上。 – MRamL

+0

没问题:)。除非有人要回答,否则我应该在短时间内为你答复。 – CodyMR

回答

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依次用于eq1每次出现。然后我们可以使用row_number() over partition来获得我们的柜台。

Here is an example使用SQL Server

+0

看起来不错。并与超过100行的作品。我会试试这个。谢谢! – MRamL

+0

您还可以更新x以获取组,然后从更新的表中进行选择。这种方法更有意义,如果您希望其他更新/选择只是让我知道,上述方法是'一体式解决方案'。 – EoinS

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); 
+0

这很美!是的,我的索引是nInd,所以我会用第二个,但两种方法都像魅力一样。非常感谢! – MRamL

+0

有趣。在某些情况下工作良好,但是如果有超过100行,则会出现此错误:“语句完成前,最大递归100已耗尽”。 – MRamL

+0

@MRamL权利。忘了这一点,因为我从未在我自己的疑问中达到最大值。把'OPTION(MAXRECURSION 0)'放在末尾(在'cte'之后) – CodyMR

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

希望它有帮助。

+0

谢谢。但它已经在存储过程中使用游标实现了。我正试图优化它。 :) – MRamL

0

望着这一个稍微不同的方式(这可能不是真实的,但消除了递归的CTE的游标的需要),它看起来像你建立你的数据集内的序群。因此,首先找到这些群体,然后确定每个群体的排序。

真正的关键是确定找到纠正分组的规则。根据您的描述和评论,我猜分组是从一开始(由nInd列排序)在每一行与和1eq值结束,所以你可以这样做:

;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