在二进制序列中捕获最后一组1的第一个字符第二部分:多个ID

时间:2017-06-23 13:23:11

标签: tsql

我的数据是这样的:

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

使用t-SQL,我试图捕获与每个ID的最后一组1中的第一个STATUS = 1对应的月份,即本例中的9月,11月和12月。

以下是我使用的代码:

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

但是,这只会返回最后一个实现STATUS = 1的实例,作为最后一组1的前1个,在本例中为1月。

我尝试过使用CASE语句并以各种组合进行分组(因此将数据读入#Temp1的中间步骤),但无法获得所有三个ID的结果;有人能帮忙吗?

提前致谢!

2 个答案:

答案 0 :(得分:1)

假设六月的Ju和七月的Jl:

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

如果月份名称在6月份的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

答案 1 :(得分:1)

您可以使用几个派生表来执行此操作,这些表将两个窗口函数堆叠在一起(不能在同一个select中完成)。我假设您的数据与您提供的表略有不同,具体取决于查询中的列名。如果它们不像我下面的那样,我强烈建议您查看如何存储数据:

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