SQL: finding the largest space in a date

I have a table with two fields: unique identifier, user identifier (foreign key) and date-time. This is a service access log. I work in SQL Server, but I would appreciate agnostic answers.

I would like to use SQL to find for a specific user the identifier with which the longest space begins.

So, let's say my values ​​are as follows (simplification for one user):

ID |  User-ID |  Time
----------------------------------
1  |  1       |  11-MAR-09, 8:00am
2  |  1       |  11-MAR-09, 6:00pm
3  |  1       |  13-MAR-09, 7:00pm
4  |  1       |  14-MAR-09, 6:00pm

If I look for the longest space for user 1, I get ID 2 (it would also be nice to get the length of the space right there and then, but much less critical).

What is the most efficient way to achieve this in SQL?

Note: the identifier is not necessarily sequential.

thanks

+5
source share
4

Database-agnostic, - richardtallent, .

:

create table test(id int, userid int, time datetime)
insert into test values (1, 1, '2009-03-11 08:00')
insert into test values (2, 1, '2009-03-11 18:00')
insert into test values (3, 1, '2009-03-13 19:00')
insert into test values (4, 1, '2009-03-14 18:00')

( SQL Server 2008, )

:

select 
  starttime.id as gapid, starttime.time as starttime, endtime.time as endtime, 
  /* Replace next line with your DB way of calculating the gap */
  DATEDIFF(second, starttime.time, endtime.time) as gap
from 
  test as starttime
inner join test as endtime on 
  (starttime.userid = endtime.userid) 
  and (starttime.time < endtime.time) 
left join test as intermediatetime on 
  (starttime.userid = intermediatetime.userid) 
  and (starttime.time < intermediatetime.time) 
  and (intermediatetime.time < endtime.time) 
where 
  (intermediatetime.id is null)

:

gapid  starttime                endtime                  gap
1      2009-03-11 08:00:00.000  2009-03-11 18:00:00.000  36000
2      2009-03-11 18:00:00.000  2009-03-13 19:00:00.000  176400
3      2009-03-13 19:00:00.000  2009-03-14 18:00:00.000  82800

.

: , richardtallent answer, , " " - ( 1 + 2, 1 + 3, 1 + 4, 2 + 3, 2 + 4, 3 + 4). , , (1 + 2 + null, 1 + 3 + 2, 1 + 4 + 2, 1 + 4 + 3, 2+ 3 + null, 2 + 4 + 3, 3 + 4 + null). WHERE, , ( ), , 1 + 2 + null, 2 + 3 + null 3 + 4 + null. -!

, , ( "" 0), , . ID -, , ,

and (starttime.time < intermediatetime.time) 

and ((starttime.time < intermediatetime.time) 
  or ((starttime.time = intermediatetime.time) and (starttime.id < intermediatetime.id)))

, 'id' .

, , ( , " " - , , , , , , ), ID , .

+10

, :

with cte_ranked as (
select *, row_number() over (partition by UserId order by Time) as rn
from table)
select l.*, datediff(minute, r.Time, l.Time) as gap_length
from cte_ranked l join cte_ranked r on l.UserId = r.UserId and l.rn = r.rn-1

, ..

Mac . , , 1M. :

create table access (id int identity(1,1)
    , UserId int not null
    , Time datetime not null);
create clustered index cdx_access on access(UserID, Time);
go

, :

with cte_gap as (
    select Id, UserId, a.Time, (a.Time - prev.Time) as gap
    from access a
    cross apply (
        select top(1) Time 
        from access b
        where a.UserId = b.UserId
            and a.Time > b.Time
        order by Time desc) as prev)
, cte_max_gap as (
    select UserId, max(gap) as max_gap
    from cte_gap
    group by UserId)
select g.* 
    from cte_gap g
    join cte_max_gap m on m.UserId = g.UserId and m.max_gap = g.gap
where g.UserId = 42;

1M , ~ 47 . , 1 ( ), 48 .

UserId = 42 , , ( ), 6379139 , 14 .

, UserId max ( , ):

select UserId, max(a.Time-prev.Time) as gap
    from access a
    cross apply (
        select top(1) Time 
        from access b
        where a.UserId = b.UserId
            and a.Time > b.Time
        order by Time desc
    ) as prev
group by UserId

3193448 , 6 1M-. - , , , , , max. , , on (UserId, Time), .

CTE "" ( ): ANSI SQL-99 . SQL Server datediff, . , "" " SQL, ". , cross apply . , . , CTE . , CTE:

select g.*
    from (    
        select Id, UserId, a.Time, (a.Time - (
            select top(1) Time 
            from access b
            where a.UserId = b.UserId
                and a.Time > b.Time
            order by Time desc
        )) as gap
        from access a) as g
    join (
        select UserId, max(gap) as max_gap
            from (
                select Id, UserId, a.Time, (a.Time - (
                   select top(1) Time 
                   from access b
                   where a.UserId = b.UserId
                     and a.Time > b.Time
                   order by Time desc
                   )) as gap
            from access a) as cte_gap
        group by UserId) as m on m.UserId = g.UserId and m.max_gap = g.gap
    where g.UserId = 42

, , LOL. , CTE. , 5-6 CTE , .

, , ( , ):

select UserId, max(gap)
    from (
        select UserId, a.Time-(
            select top(1) Time 
            from access b
            where a.UserId = b.UserId
                and a.Time > b.Time
            order by Time desc) as gap
    from access a) as gaps
group by UserId
+3

, .

, , , .

 SELECT t1.id, t1.[user-id], t1.time, (t2.time - t1.time) AS GapTime
 FROM
     t AS t1
     INNER JOIN t AS t2 ON t1.[user-id] = t2.[user-id]
 WHERE
     t1.time < t2.time
     AND NOT EXISTS (SELECT NULL FROM t AS t3 WHERE t3.[user-id] = t1.[user-id]
         AND t3.time > t2.time)
     AND NOT EXISTS (SELECT NULL FROM t AS t4 WHERE t4.[user-id] = t1.[user-id]
         AND t4.time < t1.time)

:

  • , 0 1 .
  • , /.
  • , .

# 2 , "t1.time < t2.time" "t1.time <= t2.time", 0, .

+1

RichardTallent...

SELECT
   t1.id,
   t1.[user-id],
   t1.time,
   DATEDIFF(s, t1.time, t2.time) AS GapTime
FROM
   t AS t1
INNER JOIN
   t AS t2
      ON  t2.[user-id] = t1.[user-id]
      AND t2.time = (
         SELECT
            MIN(time)
         FROM
            t
         WHERE
            [user-id] = t1.[user-id]
            AND time > t1.time
      )


AS, t2, , ...

SELECT
   t1.id,
   t1.[user-id],
   t1.time,
   DATEDIFF(
      s,
      t1.time,
      (
         SELECT
            MIN(time)
         FROM
            t
         WHERE
            [user-id] = t1.[user-id]
            AND time > t1.time
      )
   ) AS GapTime
FROM
   t1


, . , , , , "".

, GapTime 0:
- '12: 00 '( 1 )
- '12: 01 '( 0 )
- '12: 01 '( 0 )
- '12: 01 '( 0 )
- '12: 01 '( 1 )
- '12: 02 '( NULL )

, "", . , "id" , , , reocrd "", .

SELECT
   t1.id,
   t1.[user-id],
   t1.time,
   DATEDIFF(
      s,
      t1.time,
      (
         SELECT
            MIN(time)
         FROM
            t
         WHERE
            [user-id] = t1.[user-id]
            AND
            (
               (time > t1.time)
               OR
               (time = t1.time AND id > t1.id)
            )
      )
   ) AS GapTime
FROM
   t1
+1
source

All Articles