简体   繁体   中英

datediff for row that meets my condition only once per row

I want to do a datediff between 2 dates on different rows only if the rows have a condition.

my table looks like the following, with additional columns (like guid)

Id  | CreateDateAndTime        | condition
---------------------------------------------------------------
1   | 2018-12-11 12:07:55.273  |    with this 
2   | 2018-12-11 12:07:53.550  |    I need to compare this state 
3   | 2018-12-11 12:07:53.550  |    with this 
4   | 2018-12-11 12:06:40.780  |    state 3
5   | 2018-12-11 12:06:39.317  |    I need to compare this state 

with this example I would like to have 2 rows in my selection which represent the difference between the dates from id 5-3 and from id 2-1.

As of now I come with a request that gives me the difference between dates from id 5-3 , id 5-1 and id 2-1 :

with t as (
      SELECT TOP (100000) 
          *
      FROM mydatatable

      order by CreateDateAndTime desc) 

      select 
      DATEDIFF(SECOND, f.CreateDateAndTime, s.CreateDateAndTime)  time

      from t f
      join t s on (f.[guid] = s.[guid] )
      where f.condition like '%I need to compare this state%'
      and s.condition like '%with this%'
        and (f.id - s.id) < 0 

My problem is I cannot set f.id - s.id to a value since other rows can be between the ones I want to make the diff on.

How can I make the datediff only on the first rows that meet my conditions?

EDIT : To make it more clear

My condition is an eventname and I want to calculate the time between the occurence of my event 1 and my event 2 and fill a column named time for example.

@Salman A answer is really close to what I want except it will not work when my event 2 is not happening (which was not in my initial example)

ie in table like the following , it will make the datediff between row id 5 and row id 2

Id  | CreateDateAndTime        | condition
---------------------------------------------------------------
1   | 2018-12-11 12:07:55.273  |    with this 
2   | 2018-12-11 12:07:53.550  |    I need to compare this state 
3   | 2018-12-11 12:07:53.550  |    state 3
4   | 2018-12-11 12:06:40.780  |    state 3
5   | 2018-12-11 12:06:39.317  |    I need to compare this state 

the code I modified :

WITH cte AS (
    SELECT id
         , CreateDateAndTime AS currdate
         , LAG(CreateDateAndTime) OVER (PARTITION BY guid ORDER BY id desc ) AS prevdate
         , condition
    FROM t
    WHERE condition IN ('I need to compare this state', 'with this ')
)
SELECT *
     ,DATEDIFF(second, currdate, prevdate) time
FROM cte
WHERE condition = 'I need to compare this state '
and DATEDIFF(second, currdate, prevdate) != 0
order by id desc

try by using analytic function lead()

    with cte as
(
select 1 as id, '2018-12-11 12:07:55.273' as CreateDateAndTime,'with this' as condition union all
select 2,'2018-12-11 12:07:53.550','I need to compare this state' union all
select 3,'2018-12-11 12:07:53.550','with this' union all
select 4,'2018-12-11 12:06:40.780','state 3' union all
select 5,'2018-12-11 12:06:39.317','I need to compare this state'


) select *, 
    DATEDIFF(SECOND,CreateDateAndTime,lead(CreateDateAndTime) over(order by Id))
    from cte    
     where condition in ('with this','I need to compare this state')

Perhaps you want to match ids with the nearest smaller id. You can use window functions for this:

WITH cte AS (
    SELECT id
         , CreateDateAndTime AS currdate
         , CASE WHEN LAG(condition) OVER (PARTITION BY guid ORDER BY id) = 'with this'
                THEN LAG(CreateDateAndTime) OVER (PARTITION BY guid ORDER BY id) AS prevdate
         , condition
    FROM t
    WHERE condition IN ('I need to compare this state', 'with this')
)
SELECT *
     , DATEDIFF(second, currdate, prevdate)
FROM cte
WHERE condition = 'I need to compare this state'

The CASE expression will match this state with with this . If you have mismatching pairs then it'll return NULL.

You Ideally want LEADIF/LAGIF functions, because you are looking for the previous row where condition = 'with this'. Since there are no LEADIF/LAGIF I think the best option is to use OUTER/CROSS APPLY with TOP 1 , eg

CREATE TABLE #T (Id INT, CreateDateAndTime DATETIME, condition VARCHAR(28));    
INSERT INTO #T (Id, CreateDateAndTime, condition)
VALUES
    (1, '2018-12-11 12:07:55', 'with this'),
    (2, '2018-12-11 12:07:53', 'I need to compare this state'),
    (3, '2018-12-11 12:07:53', 'with this'),
    (4, '2018-12-11 12:06:40', 'state 3'),
    (5, '2018-12-11 12:06:39', 'I need to compare this state');


SELECT  ID1 = t1.ID,
        Date1 = t1.CreateDateAndTime,
        ID2 = t2.ID,
        Date2 = t2.CreateDateAndTime,
        Difference = DATEDIFF(SECOND, t1.CreateDateAndTime, t2.CreateDateAndTime)
FROM    #T AS t1
        CROSS APPLY
        (   SELECT  TOP 1 t2.CreateDateAndTime, t2.ID
            FROM    #T AS t2
            WHERE   t2.Condition = 'with this'
            AND     t2.CreateDateAndTime > t1.CreateDateAndTime
            --AND       t2.GUID = t.GUID
            ORDER BY CreateDateAndTime
        ) AS t2
WHERE   t1.Condition = 'I need to compare this state';

Which Gives:

ID1     Date1                       D2  Date2                       Difference
-------------------------------------------------------------------------------
2       2018-12-11 12:07:53.000     1   2018-12-11 12:07:55.000     2
5       2018-12-11 12:06:39.000     3   2018-12-11 12:07:53.000     74

I would enumerate the values and then use window functions for the difference.

select min(id), max(id),
       datediff(second, min(CreateDateAndTime), max(CreateDateAndTime)) as seconds
from (select t.*,
             row_number() over (partition by condition order by CreateDateAndTime) as seqnum
      from t
      where condition in ('I need to compare this state', 'with this')
      ) t
group by seqnum;

I cannot tell what you want the results to look like. This version only output the differences, with the ids of the rows you care about. The difference can also be applied to the original rows, rather than put into summary rows.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM