2016-09-15 59 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 
相關問題