当前位置: 首页 > 面试题库 >

SQL:找到最长的日期间隔

夏侯衡
2023-03-14
问题内容

我有一个包含2个字段的表:唯一ID,用户ID(外键)和日期时间。这是对服务的访问日志。我在SQL Server中工作,但我希望得到不可知论的答案。

我想使用SQL为最长间隔开始的特定用户查找ID。

因此,举例来说,假设我的值如下(为一位用户简化):

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

如果我搜索用户1的最长间隔,我将得到ID 2(也可以在那儿获得间隔的长度,但不那么关键)。

在SQL中最有效的方法是什么?

注意:ID不一定是顺序的。

谢谢


问题答案:

与数据库无关,是richardtallent的一种变体,但没有限制。(我在这里使用SQLServer 2008,但这没关系。)

从此设置开始:

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')

运行此查询:

select 
  starttime.id as gapid, starttime.time as starttime, endtime.time as endtime, 
  /* Replace next line with your DB's 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

然后,您可以ORDER BY使间隙表达式下降,然后选择最高的结果。

一些解释:

  • 就像richardtallent的答案一样,您将表格连接到其自身上以查找“较晚的”记录。这基本上是将所有记录与其以后的任何记录配对,这里将{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}。a!

正如Dems所指出的那样,如果您可能两次在其中有相同的时间(“ gap”为0),那么您将需要一种打破平局的方法。如果您可以将ID用作平局,则更改例如

and (starttime.time < intermediatetime.time)

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

假设“ id”是打破平局的有效方法。

实际上,如果您 知道 ID将单调增加(我知道您说的是“不连续”,但是尚不清楚这是否意味着它们不会随每一行增加,或者仅仅是两个相关条目的ID可能会增加)
(例如,另一个用户之间有条目),因此您可以使用ID而不是时间来进行 所有 比较,从而使操作更加简单。



 类似资料:
  • 我的域和日期字段更新了,我想通过它进行搜索

  • 我得到了一个有这样数据的表: 如何选择具有适当id的行,其中date_from和date_to之间的s_date最接近date_from\date_to范围?在我的情况下,最合适的行必须是: 谢谢!

  • 问题内容: 将记录插入数据库时​​,我无法将C#日期时间 7/31/2017 3:13:49 PM转换 为SQL日期时间。 我正在使用 但这给了我错误。 无法将字符串识别为有效的DateTime。 问题答案: .Net 直接映射到SQL Server 。这意味着您完全不需要担心显示格式,因为它没有显示格式。 您需要做的就是将struct的实例 作为参数 传递给:

  • 问题内容: 我有一个数据库,它将具有标准sql格式的UMT时间戳。如何提取数据并为其设置Java日期对象? 据我所知mysql是 至于Java,日期/时间的东西一直躲着我。 如果有人为此知道一个好的图书馆,我欢迎您提出建议。 问题答案: 为什么不直接阅读为 看到

  • 问题内容: 如何将特定日期从Java存储到数据库?(不仅是今天的日期,而且还有用户想要指定的一些日期) 问题答案: 用 类型和被假定分别用于设置日期和时间戳字段。阅读他们的文档,了解它们之间以及与和之间的区别。 通常,您会从用户那里获得一个Java日期()。您使用将该时间转换为自纪元以来的毫秒数,然后转换回a 或如我所示。

  • 问题内容: 假设您有一个包含标识符,开始时间和结束时间的表。这些开始和结束时间可以是任何时间长度。开始时间总是早于结束时间。假设没有空值。 哪种查询会告诉我最“受欢迎”的时间,即每行中的两个范围与其他大多数行重叠的地方? 现实生活中的应用是,它是一个记录用户登录和注销时间的表格。我想编写一个查询,该查询将告诉我何时有最多并发用户登录,并查看这段时间。 谢谢你。 问题答案: 这是使用简单自连接和a的