获取开始和结束位置以及日期Sql server 2012

时间:2017-03-31 06:32:10

标签: sql sql-server sql-server-2008 sql-server-2012

我想转换此查询以将GRP启动到End Grp并将开始日期启动到结束日期。

select * from (
 select z.ZoneGroupId, zs.ObjectId,z.Name,case when zs.Inside=0 then 'Left' else 'Entered' end Crossing ,zs.TimeFirst
from  zs join 
 z on zs.Zid=z.Zid
where zs.ObjectId=5696 and    z.ZoneGroupId in (1095,1096) and convert(date,zs.TimeFirst)>='2016/07/01'     ) s
where   (ZoneGroupId=1096 and s.Crossing='Entered') or (ZoneGroupId=1095 and s.Crossing='Left')

2表涉及查询

表Z

  Zid(int)   Name(varchar)  ZoneGroupId (int)
   59         Oil            1095
   60         ENR            1096
   61         NRL            1096

表Zs

  zsid(int)  zid(int)  ObjectId(int)   Timefirst(datetime)  Inside(boolan)

    1         60         1988           2016-07-01 00:39      1
    2         59         1988           2016-07-05 15:47      0         
    3         61         1988           2016-07-06 22:54      1      
    4         59         1988           2016-07-09 13:40      0         
    5         60         1988           2016-07-10 07:58      1      
    6         59         1988           2016-07-13 10:30      0         
    7         59         1988           2016-09-10 10:21      0     
    8         59         1990           2016-07-05 15:47      0         
    9         61         1990           2016-07-06 22:54      1 

我从上面的查询中得到的结果

  ZoneGroupId   ObjectId  Name   Crossing         TimeFirst
    1096        1988      ENR     Entered        2016-07-01 00:39
    1095        1988      Oil     Left           2016-07-05 15:47
    1096        1988      NRL     Entered        2016-07-06 22:54
    1095        1988      Oil     Left           2016-07-09 13:40
    1096        1988      ENR     Entered        2016-07-10 07:58
    1095        1988      Oil     Left           2016-07-13 10:30
    1095        1988      Oil     Left           2016-09-10 10:21
    1095        1990      Oil     Left           2016-07-05 15:47
    1096        1990      NRL     Entered        2016-07-06 22:54

必填结果

 ObjectId  StartName     StartDate            EndName     EndDate
 1988      Null           Null                 ENR      2016-07-01 00:39
 1988      Oil          2016-07-05 15:47       NRL      2016-7-06 22:54
 1988      Oil          2016-07-09 13:40       ENR      2016-07-10 07:58
 1988      Oil          2016-07-13 10:30       Null        Null
 1988      Oil          2016-09-10 10:21       Null        Null
 1988      Oil          2016-07-05 15:47       NRL      2016-7-06 22:54

1 个答案:

答案 0 :(得分:1)

首先是您的示例数据 - 请在将来将此问题包括在内。

declare @z table (Zid int, Name nvarchar(3), ZoneGroupId int);
insert into @z values
(59, 'Oil', 1095),
(60, 'ENR', 1096),
(61, 'NRL', 1096);

declare @zs table(zsid int, zid int, ObjectId  int, Timefirst datetime, Inside bit);
insert into @zs values
(   1, 60, 1988,   '2016-07-01 00:39', 1),
(    2, 59, 1988,   '2016-07-05 15:47', 0 ),
(    3, 61, 1988,   '2016-07-06 22:54', 1 ),
(    4, 59, 1988,   '2016-07-09 13:40', 0 ),
(    5, 60, 1988,   '2016-07-10 07:58', 1 ),
(    6, 59, 1988,   '2016-07-13 10:30', 0 ),
(    7, 59, 1988,   '2016-09-10 10:21', 0  ),
(    8, 59, 1990,   '2016-07-05 15:47', 0 ),
(    9, 61, 1990,   '2016-07-06 22:54', 1 );

然后,我使用common-table-expressions将数据拆分为2个表leftentered。添加行号以按时间顺序排列。

将表连接在一起,并使用完整的外连接(从两侧获取所有行)。在连接上指定以下条件:

  1. ObjectIds匹配
  2. Entered.TimeFirst是比Left.TimeFirst
  3. 更大的最小值
  4. Left.TimeFirst是最小的一个,小于incoming.TimeFirst
  5. 为了清楚起见,我还添加了一个订单。这是查询。

    with entered as (
        select z.ZoneGroupId
             , zs.ObjectId
             , z.Name
             , 'Entered' Crossing
             , zs.TimeFirst
             , ROW_NUMBER() over (partition by ObjectID order by zs.TimeFirst) row_no
        from @zs zs 
        inner join @z z on zs.Zid=z.Zid
        where zs.Inside <> 0 and (z.ZoneGroupId = 1096 and convert(date,zs.TimeFirst)>='2016/07/01')
    ), [left] as (
        select z.ZoneGroupId
             , zs.ObjectId
             , z.Name
             , 'Left' Crossing
             , zs.TimeFirst
             , ROW_NUMBER() over (partition by ObjectID order by zs.TimeFirst) row_no
        from @zs zs 
        inner join @z z on zs.Zid=z.Zid
        where zs.Inside = 0 and (z.ZoneGroupId = 1095 and convert(date,zs.TimeFirst)>='2016/07/01')
    )
    select * 
    from [left] 
    full outer join entered 
        on entered.row_no = (select MIN(row_no) from entered e
                              where e.TimeFirst > [left].TimeFirst
                              and e.ObjectId = [left].ObjectId)
        and [left].row_no = (select max(row_no) from [left] l
                              where l.TimeFirst < entered.TimeFirst
                              and l.ObjectId = entered.ObjectId)
        and [left].ObjectId = [entered].ObjectId
    order by isnull([left].ObjectId,entered.ObjectId), ISNULL([left].TimeFirst,entered.TimeFirst)