在SQL中,如何获取满足条件的下一行的值

时间:2017-10-31 20:04:12

标签: sql-server tsql

我有一个包含以下列的表格x

Message  TimeEvent   TriggerValue  TimeStamp
 m1         t1           1          2017-10-18 13:28:43.993
 m1         t1           1          2017-10-18 13:28:53.787
 m1         t1           1          2017-10-18 13:29:53.787
                         0          2017-10-18 13:30:53.787

如果我想在TriggerValue为1时找到时间的持续时间(当触发值为0和t1时TimeStamp之间的时间差),我该怎么办...就像我必须返回

m1   t1  duration

当我在第3行时,如果第4行Triggervalue为0,那么我减去TimeStamp和t1。我觉得我需要使用LEAD功能,但不知道如何在where子句中使用它。

任何想法都将不胜感激。

2 个答案:

答案 0 :(得分:3)

您的要求有点模糊,DDL,样本数据和所需的输出使我们更容易为您提供帮助。有关详细信息,请查看此article

要获得持续时间,我们需要一个开始和结束日期,我们需要能够按某种方式进行分组。对于我下面的解决方案,我将按消息分组。持续时间我会假设你正在寻找秒;如果没有,它将很容易调整。

LEAD(& LAG)对您没有帮助,因为他们使用静态值来说明前进或后退的行数。例如。 LAG(col1, 1)说“前一行”或LEAD(col1,5)说“前五行”。但是,你不能说,“给我下一行的值是”x“。注意这个例子:

declare @table table (someNbr int);
insert @table(someNbr) values (5),(10),(12),(15),(20);

select 
  someNbr, 
  PreviousRow  = LAG(someNbr,1) over (order by someNbr),
  twoRowsBack  = LAG(someNbr,2) over (order by someNbr),
    [ |]            = '|',
  someNbr, 
    nextRow      = LEAD(someNbr,1) over (order by someNbr),
  twoRowsAhead = LEAD(someNbr,2) over (order by someNbr)
from @table;

<强>结果:

someNbr     PreviousRow twoRowsBack  |   someNbr     nextRow     twoRowsAhead
----------- ----------- ----------- ---- ----------- ----------- ------------
5           NULL        NULL        |    5           10          12
10          5           NULL        |    10          12          15
12          10          5           |    12          15          20
15          12          10          |    15          20          NULL
20          15          12          |    20          NULL        NULL

您正在寻找的内容可以通过简单的分组或分区来处理。这是我放在一起的东西:

示例数据

if object_id('tempdb..#x') is not null drop table #x;
select * into #x 
from (values 
('m2', 't1', 1, '2017-10-18 11:26:43.222'), 
('m2', 't1', 1, '2017-10-18 11:28:52.780'),
('m2', 't1', 1, '2017-10-18 11:29:53.709'),
('m2', 't1', 0, '2017-10-18 11:31:53.781'),
('m1', 't1', 1, '2017-10-18 13:28:43.993'), 
('m1', 't1', 1, '2017-10-18 13:28:53.787'),
('m1', 't1', 1, '2017-10-18 13:29:53.787'),
('m1', 't1', 0, '2017-10-18 13:30:53.787'))
v([Message], [TimeEvent], TriggerValue, [TimeStamp]);

create clustered index uq_cl_x on #x([Message], [TimeStamp]);

我的解决方案

select [Message], [TimeEvent], Duration = datediff(second, minTime, maxTime)
from 
(
  select [Message], [TimeEvent], 
    rn      = row_number() over (partition by [message] order by [timestamp]),
    minTime = min(timeStamp) over (partition by [message] order by [timeStamp]),
    maxTime = max(case TriggerValue when 0 then [timestamp] end) over (partition by [Message] order by (select 1))
  from #x
) x
where rn=1;

<强>结果

Message TimeEvent Duration
------- --------- -----------
m1      t1        130
m2      t1        310

有几点需要注意: 1.我正在使用ROW_NUMBER来获取不同的值,而不需要在执行计划中进行排序(更好的性能)。我可以通过删除row_number逻辑并使用DISTINCT来获得相同的结果,但它会更慢。 2.我的窗口子句中有ORDER BY语句(例如minTime = min(timeStamp) over (partition by [message] order by [timeStamp]));这些不是必需的,但也会提高性能。

答案 1 :(得分:-1)

只要Timestamp列具有Datetime数据类型,您就可以相互减去它们。你将需要一种方法来识别你减去Triggervalue为1的三个时间戳中的哪一个,所以我为这个例子设置了ID = 3。

<ProjectExtensions>
    <VisualStudio>
      <FlavorProperties GUID="{349c5851-65df-11da-9384-00065b846f21}">
        <WebProjectProperties>
          <UseIIS>True</UseIIS>
          <AutoAssignPort>True</AutoAssignPort>
          <DevelopmentServerPort>15165</DevelopmentServerPort>
          <DevelopmentServerVPath>/</DevelopmentServerVPath>
          <IISUrl>http://localhost:15165/</IISUrl>
          <NTLMAuthentication>False</NTLMAuthentication>
          <UseCustomServer>False</UseCustomServer>
          <CustomServerUrl>
          </CustomServerUrl>
          <SaveServerSettingsInUserFile>False</SaveServerSettingsInUserFile>
        </WebProjectProperties>
      </FlavorProperties>
    </VisualStudio>
  </ProjectExtensions>