2013-04-21 58 views
3

我使用的是SQL Server 2008 R2和我有以下數據集:T-SQL來創建一個ID列

+---------+--------------+--------------+----------+------------+------------+ 
| Dossier | refmouvement | refadmission | refunite | datedeb | datefin | 
+---------+--------------+--------------+----------+------------+------------+ 
| P0|   2567 |   1234 |  227 | 2012-01-01 | 2012-01-02 | 
| P0|   2568 |   1234 |  227 | 2012-01-02 | 2012-01-03 | 
| P0|   2569 |   1234 |  224 | 2012-01-03 | 2012-01-06 | 
| P0|   2570 |   1234 |  232 | 2012-01-06 | 2012-01-10 | 
| P0|   2571 |   1234 |  232 | 2012-01-10 | 2012-01-15 | 
| P0|   2572 |   1234 |  232 | 2012-01-15 | 2012-01-20 | 
| P0|   2573 |   1234 |  232 | 2012-01-20 | 2012-01-25 | 
| P0|   2574 |   1234 |  224 | 2012-01-25 | 2012-01-29 | 
| P0|   2575 |   1234 |  227 | 2012-01-29 | 2012-02-05 | 
| P0|   2576 |   1234 |  227 | 2012-02-05 | 2012-02-10 | 
| P0|   2577 |   1234 |  232 | 2012-02-10 | 2012-02-15 | 
| P0|   2578 |   1234 |  201 | 2012-02-15 | 2012-02-26 | 
+---------+--------------+--------------+----------+------------+------------+ 

該數據集由datedeb下令,否則稱爲startdate

正如你可以看到這是一個連續的數據集,其中datefin等於下一行的datedeb

我需要創建一個ID列將會給基礎上,refunite一個唯一的ID和datedeb列狀這樣的:

+----+---------+--------------+--------------+----------+------------+------------+ 
| ID | Dossier | refmouvement | refadmission | refunite | datedeb | datefin | 
+----+---------+--------------+--------------+----------+------------+------------+ 
| 1 | P0|   2567 |   1234 |  227 | 2012-01-01 | 2012-01-02 | 
| 1 | P0|   2568 |   1234 |  227 | 2012-01-02 | 2012-01-03 | 
| 2 | P0|   2569 |   1234 |  224 | 2012-01-03 | 2012-01-06 | 
| 3 | P0|   2570 |   1234 |  232 | 2012-01-06 | 2012-01-10 | 
| 3 | P0|   2571 |   1234 |  232 | 2012-01-10 | 2012-01-15 | 
| 3 | P0|   2572 |   1234 |  232 | 2012-01-15 | 2012-01-20 | 
| 3 | P0|   2573 |   1234 |  232 | 2012-01-20 | 2012-01-25 | 
| 4 | P0|   2574 |   1234 |  224 | 2012-01-25 | 2012-01-29 | 
| 5 | P0|   2575 |   1234 |  227 | 2012-01-29 | 2012-02-05 | 
| 5 | P0|   2576 |   1234 |  227 | 2012-02-05 | 2012-02-10 | 
| 6 | P0|   2577 |   1234 |  232 | 2012-02-10 | 2012-02-15 | 
| 7 | P0|   2578 |   1234 |  201 | 2012-02-15 | 2012-02-26 | 
+----+---------+--------------+--------------+----------+------------+------------+ 

我只是不能換我的頭周圍RANK()ROW_NUMBER()DENSE_RANK()功能或一個組合可以實現這一點,我已經到處找,但I C ANNOT發現了什麼,也許我沒有使用正確的關鍵字,但我無法弄清楚

任何幫助將不勝感激

感謝。

下面是我試過到目前爲止代碼:

SELECT 
    ROW_NUMBER() over(order by t1.[datedeb]) as [ID1], 
    dense_Rank() over(partition by t1.[refunite] order by t1.[datedeb]) as [ID2], 
    t1.[Dossier] 
    ,t1.[refmouvement] 
    ,t1.[refadmission] 
    ,t1.[refunite] 
    ,t1.[datedeb] 
    ,t1.[datefin] 
    ,t2.[refmouvement] as [prev_refmouvement] 
    ,t2.refunite as prev_refunite 
FROM [sometable] t1 
LEFT OUTER JOIN [sometable] t2 /*self join*/ 
    ON t2.datefin = t1.datedeb 
     AND t1.[refadmission] = t2.[refadmission] 
ORDER BY 
    t1.[datedeb] 

這是它給了我:

+-----+-----+---------+--------------+--------------+----------+------------+------------+-------------------+---------------+ 
| ID1 | ID2 | Dossier | refmouvement | refadmission | refunite | datedeb | datefin | prev_refmouvement | prev_refunite | 
+-----+-----+---------+--------------+--------------+----------+------------+------------+-------------------+---------------+ 
| 1 | 1 | P0|   2567 |   1234 |  227 | 2012-01-01 | 2012-01-02 | NULL    | NULL   | 
| 2 | 2 | P0|   2568 |   1234 |  227 | 2012-01-02 | 2012-01-03 | 2567    | 227   | 
| 3 | 1 | P0|   2569 |   1234 |  224 | 2012-01-03 | 2012-01-06 | 2568    | 227   | 
| 4 | 1 | P0|   2570 |   1234 |  232 | 2012-01-06 | 2012-01-10 | 2569    | 224   | 
| 5 | 2 | P0|   2571 |   1234 |  232 | 2012-01-10 | 2012-01-15 | 2570    | 232   | 
| 6 | 3 | P0|   2572 |   1234 |  232 | 2012-01-15 | 2012-01-20 | 2571    | 232   | 
| 7 | 4 | P0|   2573 |   1234 |  232 | 2012-01-20 | 2012-01-25 | 2572    | 232   | 
| 8 | 2 | P0|   2574 |   1234 |  224 | 2012-01-25 | 2012-01-29 | 2573    | 232   | 
| 9 | 3 | P0|   2575 |   1234 |  227 | 2012-01-29 | 2012-02-05 | 2574    | 224   | 
| 10 | 4 | P0|   2576 |   1234 |  227 | 2012-02-05 | 2012-02-10 | 2575    | 227   | 
| 11 | 5 | P0|   2577 |   1234 |  232 | 2012-02-10 | 2012-02-15 | 2576    | 227   | 
| 12 | 1 | P0|   2578 |   1234 |  201 | 2012-02-15 | 2012-02-26 | 2577    | 232   | 
+-----+-----+---------+--------------+--------------+----------+------------+------------+-------------------+---------------+ 

Shaz

回答

2
DECLARE @Results TABLE(
    RowNum INT PRIMARY KEY, 
    refunite INT NOT NULL, 
    datedeb DATETIME NOT NULL 
); 

INSERT @Results (RowNum, refunite, datedeb) 
SELECT ROW_NUMBER() OVER(ORDER BY datedeb) AS RowNum, 
     refunite, 
     datedeb 
FROM dbo.MyTable; 

WITH CTERecursive 
AS (
    SELECT crt.RowNum, 
      crt.refunite, 
      crt.datedeb, 
      1 AS Rnk -- Starting rank 
    FROM @Results crt 
    WHERE crt.RowNum = 1 
    UNION ALL 
    SELECT crt.RowNum, 
      crt.refunite, 
      crt.datedeb, 
      CASE WHEN prev.refunite = crt.refunite THEN prev.Rnk ELSE prev.Rnk + 1 END 
    FROM @Results crt INNER JOIN CTERecursive prev ON crt.RowNum = prev.RowNum + 1 
) 
SELECT * 
FROM CTERecursive 
-- OPTION(MAXRECURSION 1000); -- Uncomment this line if you change the number of recursion levels allowed (default 100) 

結果:

RowNum  refunite datedeb     Rnk 
----------- ----------- ----------------------- --- 
1   227   2012-01-01 00:00:00.000 1 
2   227   2012-01-02 00:00:00.000 1 
3   224   2012-01-03 00:00:00.000 2 
4   232   2012-01-06 00:00:00.000 3 
5   232   2012-01-10 00:00:00.000 3 
6   232   2012-01-15 00:00:00.000 3 
7   232   2012-01-20 00:00:00.000 3 
8   224   2012-01-25 00:00:00.000 4 
9   227   2012-01-29 00:00:00.000 5 
10   227   2012-02-05 00:00:00.000 5 
11   232   2012-02-10 00:00:00.000 6 
12   201   2012-02-15 00:00:00.000 7 
+0

WOW!這很棒!非常感謝!這將幫助我節省大量時間!你們真的很精英! :) – iamshazi 2013-04-21 13:56:29

2

當然,你可以在WITH中有多個表,消除表變量。 基於波格丹Sahleans的答案,你可以重寫這樣的:

WITH CTEHelper AS 
    (SELECT ROW_NUMBER() OVER(ORDER BY datedeb) AS RowNum, 
      refunite, 
      datedeb 
    FROM dbo.Sometable), 
CTERecursive AS (
     SELECT crt.RowNum, 
       crt.refunite, 
       crt.datedeb, 
       1 AS Id -- Starting rank 
     FROM CTEHelper crt 
     WHERE crt.RowNum = 1 
     UNION ALL 
     SELECT crt.RowNum, 
       crt.refunite, 
       crt.datedeb, 
       CASE WHEN prev.refunite = crt.refunite THEN prev.Id ELSE prev.Id + 1 END 
     FROM CTEHelper crt INNER JOIN CTERecursive prev ON crt.RowNum = prev.RowNum + 1 
    ) 
SELECT crt.id, 
     s.* 
FROM CTERecursive crt 
    JOIN Sometable s ON s.refunite = crt.refunite AND s.datedeb = crt.datedeb 
+0

真棒!我得到了超過我的要求!謝謝!! :) – iamshazi 2013-04-21 13:56:57

1
with sometable as (
    select * 
    from (
     values ('P0', 2567, 1234, 227, cast('2012-01-01' as date), cast('2012-01-02' as date)), 
     ('P0', 2568, 1234, 227, cast('2012-01-02' as date), cast('2012-01-03' as date)), 
     ('P0', 2569, 1234, 224, cast('2012-01-03' as date), cast('2012-01-06' as date)), 
     ('P0', 2570, 1234, 232, cast('2012-01-06' as date), cast('2012-01-10' as date)), 
     ('P0', 2571, 1234, 232, cast('2012-01-10' as date), cast('2012-01-15' as date)), 
     ('P0', 2572, 1234, 232, cast('2012-01-15' as date), cast('2012-01-20' as date)), 
     ('P0', 2573, 1234, 232, cast('2012-01-20' as date), cast('2012-01-25' as date)), 
     ('P0', 2574, 1234, 224, cast('2012-01-25' as date), cast('2012-01-29' as date)), 
     ('P0', 2575, 1234, 227, cast('2012-01-29' as date), cast('2012-02-05' as date)), 
     ('P0', 2576, 1234, 227, cast('2012-02-05' as date), cast('2012-02-10' as date)), 
     ('P0', 2577, 1234, 232, cast('2012-02-10' as date), cast('2012-02-15' as date)), 
     ('P0', 2578, 1234, 201, cast('2012-02-15' as date), cast('2012-02-26' as date)) 
    ) t (Dossier, refmouvement, refadmission, refunite, datedeb, datefin) 
), pos as (
    select d.*, (case when d2.refunite is null then null 
         when d2.refunite != d.refunite then d2.datedeb 
         else d.datedeb end) as forward, 
       (case when d3.refunite is null then null 
         when d3.refunite != d.refunite then d3.datedeb 
         else d.datedeb end) as backward 
    from sometable d 
    left outer join sometable d2 on d.refadmission = d2.refadmission and d.datefin = d2.datedeb 
    left outer join sometable d3 on d.refadmission = d3.refadmission and d.datedeb = d3.datefin 
) 
select dense_rank() over (order by isnull((select min(datedeb) 
              from pos 
              where refadmission = t.refadmission 
              and refunite = t.refunite 
              and datedeb > t.datedeb 
              and datedeb = backward 
              and ((t.datedeb = t.backward and t.datedeb = t.forward) 
                or t.datedeb != t.backward or t.backward is null) 
              and datedeb != forward), datedeb)) as ID, 
     Dossier, refmouvement, refadmission, refunite, datedeb, datefin 
from pos t 
order by datedeb