2017-06-23 9 views
1

私はこのようなデータに何かがありますキャプチャ最初の文字:複数のID

ID  1 1 1 1 1 1 1 1 1 1 1 1 
Month J F M A M J J A S O N D 
Status 1 0 0 1 0 1 0 0 1 1 1 1 

ID  2 2 2 2 2 2 2 2 2 2 2 2 
Month J F M A M J J A S O N D 
Status 1 0 1 0 1 0 1 0 1 0 1 1 

ID  3 3 3 3 3 3 3 3 3 3 3 3 
Month J F M A M J J A S O N D 
Status 0 0 0 0 0 0 0 0 0 0 0 1 

トン-SQLを使用して、私が最初に対応する月を捕獲しようとしていますこの例では9月、11月および12月のIDごとに1の最後のグループにSTATUS = 1を追加します。ここで

は、私が使用しているコードです:

IF OBJECT_ID('tempdb..#Temp1') IS NOT NULL DROP TABLE #Temp1 

;WITH PARTITIONED1 AS 

(SELECT t0.ID 
     , t0.Year_Month 
     , LAST_VALUE(t0.Year_Month) OVER (PARTITION BY t0.Account_Number ORDER BY t0.Year_Month) AS STATUS 
     , ROW_NUMBER() OVER (PARTITION BY t0.Account_Number ORDER BY t0.Year_Month) AS rn1 

FROM #Temp0 t0 
) 

SELECT * 
INTO #Temp1 
FROM PARTITIONED1 p1 
ORDER BY  t0.ID 
      , t0.Year_Month 


IF OBJECT_ID('tempdb..#Temp') IS NOT NULL DROP TABLE #Temp 

SELECT * 
INTO #Temp 
FROM #Temp1 t1 
WHERE t1.rn1 = (SELECT MAX(b.rn1) + 1 FROM #Temp1 b WHERE b.STATUS = 0)  
GROUP BY  t1.ID 
     , t1.Year_Month 
     , t1.rn1 

しかし、これはちょうどこの場合1月には、STATUS = 1は1秒の最後のグループの最初の1として全体的に達成され、最後のインスタンスを返します。

私はCASEステートメントとさまざまな組み合わせでグルーピングを試みましたが(中間のステップでデータを#Temp1に読み込みます)、3つのIDすべての結果を取得できませんでした。誰でも助けることができますか?

ありがとうございます! 7月6月とのJlのためのチュを想定し

答えて

1

--Sample Data 
IF OBJECT_ID('tempdb..#Temp0') IS NOT NULL DROP TABLE #Temp0 
CREATE TABLE #Temp0 (ID INT, Year_Month VARCHAR(1), Status INT) 
INSERT INTO #Temp0 
VALUES(1,'J',1),(1,'F',0),(1,'M',0),(1,'A',1),(1,'M',0),(1,'J',1),(1,'J',0),(1,'A',0),(1,'S',1),(1,'O',1),(1,'N',1),(1,'D',1),(2,'J',1),(2,'F',0),(2,'M',1),(2,'A',0),(2,'M',1),(2,'J',0),(2,'J',1),(2,'A',0),(2,'S',1),(2,'O',0),(2,'N',1),(2,'D',1),(3,'J',0),(3,'F',0),(3,'M',0),(3,'A',0),(3,'M',0),(3,'J',0),(3,'J',0),(3,'A',0),(3,'S',0),(3,'O',0),(3,'N',0),(3,'D',1); 


--Query 
WITH A 
AS (SELECT *, 
      CASE Year_Month 
       WHEN 'J' THEN 1 
       WHEN 'F' THEN 2 
       WHEN 'M' THEN 3 
       WHEN 'A' THEN 4 
       WHEN 'M' THEN 5 
       WHEN 'Ju' THEN 6 
       WHEN 'Jl' THEN 7 
       WHEN 'A' THEN 8 
       WHEN 'S' THEN 9 
       WHEN 'O' THEN 10 
       WHEN 'N' THEN 11 
       WHEN 'D' THEN 12 
      END 
     AS MonthNumber 
     FROM #Temp0), 
StartingPoints 
AS (SELECT ID, 
      Year_Month, 
      MonthNumber, 
      Status 
     FROM A 
     WHERE NOT EXISTS 
     (
     SELECT 1 
     FROM A 
     AS B 
     WHERE B.ID=A.ID 
       AND B.Status=A.Status-1 
    )), 
MonthRanking 
AS (SELECT A.*, 
      ROW_NUMBER() OVER(PARTITION BY A.ID ORDER BY A.MonthNumber) 
     AS rownum 
     FROM A 
     INNER JOIN 
     (
     SELECT ID, 
       MAX(MonthNumber)+1 
     AS StartOfLastGroup 
     FROM StartingPoints 
     GROUP BY ID 
    ) 
     AS B 
     ON A.ID=B.ID 
     AND A.MonthNumber>=B.StartOfLastGroup) 
SELECT * 
FROM MonthRanking 
WHERE rownum=1; 

結果:

enter image description here

月名が7月、6月のように完全に記録されている場合、これは同様に動作します:

WITH StartingPoints 
    AS (SELECT ID, 
       Year_Month, 
       MonthNUmber = MONTH('01-'+Year_Month+'-2010'), 
       Status 
     FROM #Temp0 
     WHERE NOT EXISTS 
     (
      SELECT 1 
      FROM #Temp0 AS B 
      WHERE B.ID = #Temp0.ID 
        AND B.Status = #Temp0.Status - 1 
     )), 
    MonthRanking 
    AS (SELECT A.*, 
       ROW_NUMBER() OVER(PARTITION BY A.ID ORDER BY MONTH('01-'+A.Year_Month+'-2010')) AS rownum 
     FROM #Temp0 AS A 
       INNER JOIN 
     (
      SELECT ID, 
        MAX(MonthNumber) + 1 AS StartOfLastGroup 
      FROM StartingPoints 
      GROUP BY ID 
     ) AS B ON A.ID = B.ID 
        AND MONTH('01-'+A.Year_Month+'-2010') >= B.StartOfLastGroup) 
    SELECT * 
    FROM MonthRanking 
    WHERE rownum = 1; 

結果:

enter image description here

そして、我々は、データがIamdaveは、単純にそうように、それを前提としていると仮定した場合:

WITH StartingPoints 
    AS (SELECT ID, 
       Year_Month, 
       Status 
     FROM #Temp0 
     WHERE NOT EXISTS 
     (
      SELECT 1 
      FROM #Temp0 AS B 
      WHERE B.ID = #Temp0.ID 
        AND B.Status = #Temp0.Status - 1 
     )), 
    MonthRanking 
    AS (SELECT A.*, 
       ROW_NUMBER() OVER(PARTITION BY A.ID ORDER BY Year_Month) AS rownum 
     FROM #Temp0 AS A 
       INNER JOIN 
     (
      SELECT ID, 
        MAX(Year_Month) + 1 AS StartOfLastGroup 
      FROM StartingPoints 
      GROUP BY ID 
     ) AS B ON A.ID = B.ID 
        AND A.Year_Month >= B.StartOfLastGroup) 
    SELECT * 
    FROM MonthRanking 
    WHERE rownum = 1; 

結果:あなたはカップルでこれを行うことができ

enter image description here

+0

を...これは少し複雑すぎる – iamdave

+0

@iamdaveです先頭の関数を利用するのは良いですが、SQL Serverの以前のバージョンを使用している場合はどうなりますか? 2008年に言いましょう –

+0

@iamdave島と谷を特定する必要がないので簡素化 –

1

(同じselectで実行できない)2つのウィンドウ関数を積み重ねた2つのウィンドウから導出されたテーブルを作成します。私はあなたのデータがクエリの列名に基づいて、あなたが提供したテーブルと少し異なると仮定しています。

declare @t table(ID int, YearMonth int,StatusValue bit); 
insert into @t values (1,201501,1),(1,201502,0),(1,201503,0),(1,201504,1),(1,201505,0),(1,201506,1),(1,201507,0),(1,201508,0),(1,201509,1),(1,201510,1),(1,201511,1),(1,201512,1),(2,201601,1),(2,201602,0),(2,201603,1),(2,201604,0),(2,201605,1),(2,201606,0),(2,201607,1),(2,201608,0),(2,201609,1),(2,201610,0),(2,201611,1),(2,201612,1),(3,201701,0),(3,201702,0),(3,201703,0),(3,201704,0),(3,201705,0),(3,201706,0),(3,201707,0),(3,201708,0),(3,201709,0),(3,201710,0),(3,201711,0),(3,201712,1); 

with c as 
(
    select ID 
      ,YearMonth 
      ,StatusValue 
      ,case when StatusValue = 1 
        and lead(StatusValue,1,1) over (partition by ID 
                order by YearMonth desc) = 0 
        then 1 
        else 0 
        end as c 
    from @t 
), sc as 
(
    select ID 
      ,YearMonth 
      ,StatusValue 
      ,sum(c) over (partition by ID order by YearMonth desc) as sc 
    from c 
    where c = 1 
) 
select ID 
     ,YearMonth 
     ,StatusValue 
from sc 
where sc = 1 
order by ID; 

出力::彼らは、私は以下のそれらを持っていないようならば、私は強く、あなたのデータを保存する方法を見てたお勧め

+----+-----------+-------------+ 
| ID | YearMonth | StatusValue | 
+----+-----------+-------------+ 
| 1 | 201509 |   1 | 
| 2 | 201611 |   1 | 
| 3 | 201712 |   1 | 
+----+-----------+-------------+ 
関連する問題