标记行中的连续系列

时间:2018-02-13 20:53:30

标签: sql sql-server

说我有下表:

+------------+-------+
|    Date    | Count |
+------------+-------+
| 11/25/2017 |     1 |
| 11/21/2017 |     1 |
| 11/20/2017 |     1 |
| 11/18/2017 |     1 |
| 11/10/2017 |     1 |
| 11/2/2017  |     0 |
| 10/27/2017 |     0 |
| 10/26/2017 |     1 |
| 10/21/2017 |     1 |
| 10/21/2017 |     1 |
| 10/17/2017 |     1 |
| 10/9/2017  |     0 |
| 10/2/2017  |     0 |
| 9/22/2017  |     0 |
| 9/14/2017  |     1 |
| 9/10/2017  |     1 |
| 9/10/2017  |     1 |
| 9/10/2017  |     0 |
| 9/4/2017   |     1 |
| 8/27/2017  |     1 |
| 8/19/2017  |     0 |
| 8/14/2017  |     0 |
+------------+-------+

我需要SQL查询来输出以下内容:

+------------+-------+------+
|    Date    | Count | Flag |
+------------+-------+------+
| 11/25/2017 |     1 |    1 |
| 11/21/2017 |     1 |    1 |
| 11/20/2017 |     1 |    1 |
| 11/18/2017 |     1 |    1 |
| 11/10/2017 |     1 |    1 |
| 11/2/2017  |     0 |    0 |
| 10/27/2017 |     0 |    0 |
| 10/26/2017 |     1 |    2 |
| 10/21/2017 |     1 |    2 |
| 10/21/2017 |     1 |    2 |
| 10/17/2017 |     1 |    2 |
| 10/9/2017  |     0 |    0 |
| 10/2/2017  |     0 |    0 |
| 9/22/2017  |     0 |    0 |
| 9/14/2017  |     1 |    2 |
| 9/10/2017  |     1 |    2 |
| 9/10/2017  |     1 |    2 |
| 9/10/2017  |     0 |    0 |
| 9/4/2017   |     1 |    3 |
| 8/27/2017  |     1 |    3 |
| 8/19/2017  |     0 |    0 |
| 8/14/2017  |     0 |    0 |
+------------+-------+------+

需要填充Flag列。它的值可以是0,1,2,以下是条件:

  

1 - 计数> 0,需要从最近的日期开始,直到Count = 0和         最小上限为3连续计数> 0

     

2 - 计数> 0,不是从最近的日期开始,而是检查最小上限   3连续计数> 0
       直到Count = 0

     

3 - 计数= 1,连续系列没有上限

     

0 - 当计数为0时

请帮忙

2 个答案:

答案 0 :(得分:5)

这是一个差距和岛屿问题

select date, count,
    case when count > 0 then 
          case when count(*) over (partition by grn, count) >= 3 then 
             case when max(date) over (partition by grn, count) = max_date then 1
             else 2
             end
          else 3
          end
    else 0      
    end flag
from
(
    select date, count,
           row_number() over (order by date, count)- 
           row_number() over (partition by count order by date, count) grn,
           (select max(date) from data) max_date
    from data
) t
order by date desc, count desc

iOS 10: CIKernel's ROI function did not allow tiling

该解决方案基于1的连续序列的识别,这通过创建grp列来完成。隔离连续序列后,其余部分很简单CASE

答案 1 :(得分:1)

以下脚本应该执行任务

                    declare  @test table
                    (dt date,
                     ct int
                     )

                     insert into @test values
                       ('11/25/2017' , 1 ),
                     ('11/21/2017', 1 ),
                     ('11/20/2017' ,     1), 
                     ('11/18/2017' ,     1), 
                     ('11/10/2017' ,     1),
                     ('11/2/2017' ,     0), 
                     ('10/27/2017' ,     0), 
                     ('10/26/2017' ,     1), 
                     ('10/21/2017' ,     1), 
                     ('10/21/2017' ,     1), 
                     ('10/17/2017' ,     1), 
                     ('10/9/2017'  ,     0), 
                     ('10/2/2017'  ,     0), 
                     ('9/22/2017'  ,     0), 
                     ('9/14/2017'  ,     1), 
                     ('9/10/2017'  ,     1), 
                     ('9/10/2017'  ,     1),
                     ('9/10/2017'  ,     0), 
                     ('9/4/2017'   ,     1), 
                     ('8/27/2017'  ,     1),  
                     ('8/19/2017'  ,     0), 
                     ('8/14/2017' ,      0)



                      /***********Tag a unique identifier sorted by the date column 
                      Each row will have the unique value


                      ************************/
                      Select t.*,ROW_NUMBER()over (order by dt desc)as rw ,0 as flag 
                      into #tmp
                      from @test t 
                      order by dt desc

                     -- Select * from #tmp

                      /*******Create another table to store the start and the ending of the rows where the counter has 0's
                      and create another level of identifer to track the position

                      ***********/
                      declare @trows table (zerorows int ,position int) 

                        insert into @trows
                        Select 0 , 1
                        union
                        Select t.rw,ROW_NUMBER() over (order by t.rw) + 1 from #tmp t 
                        where t.ct = 0 

                        --Select * from @trows
                    /*******

                    -- Do a self join to the position table and pick up the differences where there are at least 3 consecutive numbers

                    -- Test this query
                    Select prev.zerorows+1,nxt.zerorows,nxt.zerorows - (prev.zerorows+1) from @trows nxt 
                    inner join @trows prev on prev.position  = nxt.position - 1 
                    where nxt.zerorows - (prev.zerorows+1) >= 3    


                    *******/
                    /**********Set the 1st flag ****************/



                    update t
                    set t.flag = 1
                     from #tmp t
                    where 
                    t.rw<   
                    (   Select min(nxt.zerorows)   from @trows nxt 
                        inner join @trows prev on prev.position  = nxt.position - 1 
                        where nxt.zerorows - (prev.zerorows +1) >= 3 
                     )


                     /*******************Set the 2nd flag ***************/
                     update t
                    set t.flag = 2
                     from #tmp t
                     inner join  
                     (
                        Select nxt.zerorows as nxt,prev.zerorows as prev from @trows nxt 
                        inner join @trows prev on prev.position  = nxt.position - 1 
                        where nxt.zerorows - (prev.zerorows+1) >= 3  
                     )flagged on (t.rw between flagged.prev+1 and flagged.nxt-1) 
                     where t.flag <> 1 

                     /**************Set the 3rd flag *******************/
                    update t
                    set t.flag = 3
                     from #tmp t
                     where t.flag = 0 and t.ct = 1










                    Select * from #tmp



                      drop table #tmp