【问题标题】:Compare datetime of rows with same ID, return only columns with datetime difference less than 4 hours比较具有相同 ID 的行的日期时间,仅返回日期时间差小于 4 小时的列
【发布时间】:2015-04-07 22:57:00
【问题描述】:

我真的很难处理这个查询。任何帮助将不胜感激!

桌子:

+------+----------+--------------------+--------+-------------------+
|Ref   |Dept      |DeptTime            |Arr     |ArrTime            |
+------+----------+--------------------+--------+-------------------+
|1     |New York  |2015-02-01 08:00:00 |Boston  |2015-02-01 09:00:00|
|1     |Boston    |2015-02-01 10:00:00 |Chicago |2015-02-01 11:00:00|
|1     |Chicago   |2015-02-01 12:00:00 |Dallas  |2015-02-01 13:00:00|
|1     |Dallas    |2015-02-02 11:00:00 |Seattle |2015-02-02 13:00:00|
|2     |London    |2015-02-01 04:00:00 |Berlin  |2015-02-01 16:00:00|
|2     |Berlin    |2015-02-02 18:00:00 |Moscow  |2015-02-02 23:00:00|
+------+----------+--------------------+--------+-------------------+

此表显示多站行程。如果到达和离开之间的中途停留时间少于 4 小时,则应将其视为同一行程的一部分。目的地应该是下一个出发时间超过四个小时的第一个到达时间。在这种情况下,我想显示出发城市和出发时间,以及最终到达目的地和到达时间。您可以在此问题的底部看到所需的输出示例。

我认为查询应该做的是选择具有相同 ref 的值(使用连接?),仅比较不同行的 ArrTime 和 DeptTime,如果差异大于 4 小时,则返回 Dept、DeptTime、多站旅程的 Arr 和 ArrTime。任何超过 4 小时的时间都被视为旅程的结束。

我尝试使用几个简单的查询,但是我不知道如何计算具有相同 Ref 的不同项目之间的 Datetime 差异,以及如何比较不同行之间的 ArrTime 和 DeptTime。

我在 StackOverflow 上发现了这种比较日期时间的方法,但是我得到的只是使用它时的语法错误。

DECLARE @date1 DATETIME;
DECLARE @date2 DATETIME;

SET @date1 = '2012-04-01 08:10:16';
SET @date2 = '2012-04-10 11:35:36';

编辑:查询后的最终输出表应如下所示:

+------+----------+--------------------+--------+-------------------+
|Ref   |Dept      |DeptTime            |Arr     |ArrTime            |
+------+----------+--------------------+--------+-------------------+
|1     |New York  |2015-02-01 08:00:00 |Dallas  |2015-02-01 13:00:00|
|1     |Dallas    |2015-02-02 11:00:00 |Seattle |2015-02-02 13:00:00|
|2     |London    |2015-02-01 04:00:00 |Berlin  |2015-02-01 16:00:00|
|2     |Berlin    |2015-02-02 18:00:00 |Moscow  |2015-02-02 23:00:00|
+------+----------+--------------------+--------+-------------------+

任何帮助将不胜感激!

【问题讨论】:

  • @Strawberry 谢谢,我明白了,这些只是为了便于阅读而格式化
  • 为了获得帮助的最佳方式,使用标准格式(这里是 YYYY-MM-DD HH:MM:SS,MySQL 使用),因为它对其他用户来说更清楚。
  • 您在标题中写道,您想显示层数大于 4 小时的位置,但在描述中写下“少于 4 小时”。那你想要哪一个?
  • 抱歉搞砸了@Fenistil,我更改了标题和日期时间格式。如果有任何不清楚的地方,请告诉我。
  • 我认为在您的应用程序(如 php)中比在 MySQL 中更容易。在 SQL 中,您主要可以一次处理 1 行。所以你应该在这里使用很多子选择,这在 MySQL 中非常慢,这使得整个查询非常复杂。但如果你能在某种应用程序中做到这一点,那就很容易了。

标签: mysql sql time-series


【解决方案1】:

我会通过创建两个中间表来进行报告。

第一个叫做flight_journey。它会根据您的时间要求对每个旅程所在的航班进行分组。

第二个叫first_last。它标识了每个旅程中的第一个和最后一个航班,因为这就是您想要显示的全部内容。

最后的 select 语句仅使用带有自连接的 first_last 表来显示您想要的内容。

您可以索引中间表以提高性能。

FLIGHT_JOURNEY表:

create table flight_journey as
select z.*, @row_num := if(@prev_value=chk,@row_num+1,1) as journey
from(
select
   f.*, p.arrtime as prev_arr,
   case
when p.depttime is null then 1
when ifnull(hour(timediff(f.depttime, p.arrtime)), 0) <= 4 then
   1
else
   0
end as chk
from
   flights f
left join flights p on f.ref = p.ref
and p.depttime = (select max(z.depttime) from flights z where z.ref = p.ref and z.depttime < f.depttime)
) z,
 (select @row_num := 1) x,
      (select @prev_value := '') y
order by
   z.ref,
   z.depttime;

FIRST_LAST表:

create table first_last as
select
   y.*
from
   (select ref, journey, min(depttime) as min_dept, max(arrtime) as max_arr from flight_journey group by ref, journey) x
join flight_journey y on x.ref = y.ref
and x.journey = y.journey
and (x.min_dept = y.depttime or x.max_arr = y.arrtime);

最终选择语句:

select
   x.ref,
   x.dept,
   x.depttime,
   y.arr,
   y.arrtime
from
   first_last x
join first_last y on x.ref = y.ref
and x.journey = y.journey
and y.depttime > x.depttime
union all
   select
      x.ref,
      x.dept,
      x.depttime,
      x.arr,
      x.arrtime
   from
      first_last x
   join (select ref, journey from first_last group by ref, journey having count(*) = 1) y on x.ref = y.ref
   and x.journey = y.journey;

小提琴: http://sqlfiddle.com/#!2/f22b9/2/0

输出:

| REF |     DEPT |                        DEPTTIME |     ARR |                         ARRTIME |
|-----|----------|---------------------------------|---------|---------------------------------|
|   1 | New York | February, 01 2015 08:00:00+0000 |  Dallas | February, 01 2015 13:00:00+0000 |
|   1 |   Dallas | February, 02 2015 11:00:00+0000 | Seattle | February, 02 2015 13:00:00+0000 |
|   2 |   London | February, 01 2015 04:00:00+0000 |  Berlin | February, 01 2015 16:00:00+0000 |
|   2 |   Berlin | February, 02 2015 18:00:00+0000 |  Moscow | February, 02 2015 23:00:00+0000 |

【讨论】:

  • 我刚刚测试过它,它就像一个魅力,绝对漂亮。非常感谢@Brian DeMilia!
  • 嗨@Brian DeMilia,它实际上非常适合我的示例中的数据,但是如果您将柏林出发时间更改为同一天(因此仅两个小时后),它仍然会列出它们作为单独的旅程。您对为什么会发生这种情况有任何想法吗?
  • @Grandas 我误解了你解释旅程的方式。我认为这是4小时的旅行时间。如果中途停留> = 4小时,您实际上希望航班成为同一旅程的一部分,我现在明白了。我会重新写。
  • 抱歉,这点不够清楚,你现在是对的。真的很期待看到你是怎么做到的!
  • @Grandas 很明显,我只是更关注预期的输出而不是你的解释。我想我现在已经按照您的预期工作了。反例请参见此处:sqlfiddle.com/#!2/f4b99/1/0(需要编辑的是 flight_journey 表)
猜你喜欢
  • 1970-01-01
  • 2020-09-01
  • 1970-01-01
  • 2018-03-14
  • 2013-04-09
  • 1970-01-01
  • 1970-01-01
  • 2011-08-03
  • 1970-01-01
相关资源
最近更新 更多