根据日期时间从选定的行中获取下一行不起作用

时间:2019-03-03 03:43:49

标签: sql sql-server tsql lead

我有以下数据,我希望能够根据停止类型id将所有行放到一行中。因此,止损类型是按顺序排列的,这意味着0或2将在3之前。我相信Lead是我要使用的东西,但似乎无法像我想要的那样工作并且无法弄清楚为什么

这是基于GMT日期时间的原始数据。

OrderId          GmtDeliveryDateTime        StopTypeId
3650             2019-01-11 13:04:44.000        0       
3650             2019-01-11 14:22:09.000        3       
3650             2019-01-11 15:13:35.000        2       
3650             2019-01-11 16:05:14.000        3

我想让它看起来像这样:

OrderId  GmtDeliveryDateTime    StopTypeId   GmtDeliveryDateTime    StopTypeId
3650    2019-01-11 13:04:44.000     0       2019-01-11 14:22:09.000     3
3650    2019-01-11 15:13:35.000     2       2019-01-11 16:05:14.000     3

这是我正在使用的查询:

SELECT *
FROM (
    SELECT OrderId,
           GmtDeliveryDateTime,
           StopTypeId,        
           LEAD(StopTypeId) OVER (ORDER BY GmtDeliveryDateTime, StopTypeId) NxtStop
    FROM table
)

这是上面产生的结果:

OrderId GmtDeliveryDateTime     StopTypeId  NxtStop
3650    2019-01-11 13:04:44.000     0         2
3650    2019-01-11 15:13:35.000     2         2
3650    2019-01-11 14:22:09.000     3         3
3650    2019-01-11 16:05:14.000     3         2

我的查询出了什么问题?

5 个答案:

答案 0 :(得分:1)

如果可以保证行是交错的,则可以执行以下操作:

SELECT t.*
FROM (SELECT OrderId,
             GmtDeliveryDateTime,
             StopTypeId,        
             LEAD(GmtDeliveryDateTime) OVER (PARTITION BY OrderId ORDER BY GmtDeliveryDateTime, StopTypeId) as next_GmtDeliveryDateTime,
             LEAD(StopTypeId) OVER (PARTITION BY OrderId ORDER BY GmtDeliveryDateTime, StopTypeId) as next_StopTypeId
      FROM table t
     ) t
WHERE StopTypeId <> 3;

答案 1 :(得分:0)

假设以0,32,3作为连续止损ID的行为给定订单ID标识了一个组,您可以使用运行总和对连续0进行分类, 3或2,3行成组,然后使用group by获得所需的结果。

SELECT OrderId,
       MIN(GmtDeliveryDateTime),
       MIN(StopTypeId),
       MAX(GmtDeliveryDateTime),
       MAX(StopTypeId)
FROM (SELECT t.*,sum(case when StopTypeId=3 then 1 else 0 end) over(partition by OrderId order by GmtDeliveryDateTime) as grp
      FROM table t
     ) t 
GROUP BY OrderId,grp

答案 2 :(得分:0)

我了解到您正在尝试将记录分为两部分,每条记录与下一个记录按GmtDeliveryDateTime进行排序。

这里是一个解决方案,该解决方案在子查询中使用LAG()恢复相关值,并使用ROW_NUMBER()为每个记录分配一个数字,并按GmtDeliveryDateTime进行排序。外部查询使用行号从两条记录中过滤出一条记录(甚至行号也被过滤掉):

SELECT *
FROM (
    SELECT 
        OrderId,
        GmtDeliveryDateTime,
        StopTypeId,        
        LEAD(GmtDeliveryDateTime) OVER (ORDER BY GmtDeliveryDateTime) NxtGmtDeliveryDateTime,
        LEAD(StopTypeId) OVER (ORDER BY GmtDeliveryDateTime) NxtStopTypeId,
        ROW_NUMBER() OVER (ORDER BY GmtDeliveryDateTime) rn
    FROM mytable 
) x WHERE rn % 2 <> 0

注意:由于您的示例数据没有显示重复的ORDER BY,因此我删除了StopTypeId上的GmtDeliveryDateTime

demo on DB Fiddle 及其示例数据将返回:

<pre>
OrderId | GmtDeliveryDateTime | StopTypeId | NxtGmtDeliveryDateTime | NxtStopTypeId | rn
------: | :------------------ | ---------: | :--------------------- | ------------: | :-
   3650 | 11/01/2019 00:00:00 |          0 | 11/01/2019 00:00:00    |             3 | 1
   3650 | 11/01/2019 00:00:00 |          2 | 11/01/2019 00:00:00    |             3 | 3
</pre>

答案 3 :(得分:0)

您可以在下面尝试-

DEMO

SELECT OrderId,
       MIN(GmtDeliveryDateTime) as starttime,
       MIN(StopTypeId) as startStopTypeId,
       MAX(GmtDeliveryDateTime) as endtime,
       MAX(StopTypeId) as nextStopTypeId
       from
(
SELECT t.*,
row_number() over(order by GmtDeliveryDateTime)-
sum(case when StopTypeId=3 then 1 else 0 end) over(partition by OrderId order by GmtDeliveryDateTime) as grp
      FROM  t1 t
)A group by grp,OrderId

输出:

OrderId starttime           startStopTypeId endtime             nextStopTypeId
3650    11/01/2019 13:04:44   0             11/01/2019 14:22:09  3
3650    11/01/2019 15:13:35   2             11/01/2019 16:05:14  3

答案 4 :(得分:0)

我知道其他人已经回答了,但是我使用了您的初始查询并将其稍加修改以得到所需的结果:

DROP TABLE IF EXISTS #SO;

CREATE TABLE #SO
    (
        OrderID INT ,
        DeliveryDate DATETIME ,
        StopTypeID INT
    );

INSERT INTO #SO ( OrderID ,
                  DeliveryDate ,
                  StopTypeID )
VALUES ( 3650, '2019-01-11 13:04:44.000', 0 ) ,
       ( 3650, '2019-01-11 14:22:09.000', 3 ) ,
       ( 3650, '2019-01-11 15:13:35.000', 2 ) ,
       ( 3650, '2019-01-11 16:05:14.000', 3 );

SELECT x.OrderID ,
       x.DeliveryDate ,
       x.StopTypeID ,
       x.NxtStop ,
       ROW_NUMBER () OVER ( ORDER BY x.DeliveryDate ) AS rownumber
INTO   #TestData
FROM
       (
           SELECT OrderID ,
                  DeliveryDate ,
                  StopTypeID ,
                  LEAD ( StopTypeID ) OVER ( ORDER BY DeliveryDate , StopTypeID ) NxtStop
           FROM   #SO
       ) AS x;

SELECT a.OrderID ,
      a.DeliveryDate ,
      a.StopTypeID ,
      b.DeliveryDate ,
      b.StopTypeID
FROM  #TestData AS a
      INNER JOIN #TestData AS b ON b.OrderID = a.OrderID
                                   AND a.NxtStop = b.StopTypeID
                                   AND a.rownumber + 1 = b.rownumber
WHERE a.StopTypeID < b.StopTypeID;

DROP TABLE IF EXISTS #TestData;