SQL中的日期范围交集

时间:2010-05-05 07:25:38

标签: sql mysql database

我有一个表,其中每一行都有一个开始和结束日期时间。这些可以是任意短或长的跨度。

我想查询所有行的交集的总持续时间,以及两个开始和结束日期时间。

你怎么能在MySQL中做到这一点?

或者您是否必须选择与查询开始和停止时间相交的行,然后计算每行的实际重叠并将其与客户端相加?


举个例子,用毫秒来说明一点:

有些行:

ROW  START  STOP
1    1010   1240
2     950   1040
3    1120   1121

我们想知道这些行在1030到1100之间的总和时间。

让我们计算每一行的重叠:

ROW  INTERSECTION
1    70
2    10
3     0

所以这个例子中的总和是80。

4 个答案:

答案 0 :(得分:5)

如果你的例子在第一行中应该说70,那么

假设@range_start和@range_end作为条件参数:

SELECT SUM( LEAST(@range_end, stop) - GREATEST(@range_start, start) )
FROM Table
WHERE @range_start < stop AND @range_end > start

使用greatest /最少和date functions您应该能够获得直接操作日期类型所需的内容。

答案 1 :(得分:1)

我担心你运气不好。

由于您不知道“累积相交”的行数,因此您需要递归解决方案或聚合运算符。

您需要的聚合运算符是没有选项的,因为SQL没有它应该操作的数据类型(该类型是区间类型,如“时态数据和关系模型”中所述)。

递归解决方案可能是可能的,但它可能很难编写,难以读取给其他程序员,并且优化器是否可以将该查询转换为最佳数据访问策略也是值得怀疑的。

或者我误解了你的问题。

答案 2 :(得分:1)

如果您知道自己拥有的最长时间,那么这是一个非常有趣的解决方案。创建一个包含所有数字的表格,从一个到最长时间。

millisecond
-----------
1
2
3
...
1240

将其称为time_dimension(此技术通常用于数据仓库中的维度建模。)

然后这个:

SELECT 
  COUNT(*) 
FROM 
  your_data 
    INNER JOIN time_dimension ON time_dimension.millisecond BETWEEN your_data.start AND your_data.stop
WHERE 
  time_dimension.millisecond BETWEEN 1030 AND 1100

...将为您提供1030到1100之间的总运行时间毫秒数。

当然,您是否可以使用此技术取决于您是否可以安全地预测数据中的最大毫秒数。

正如我所说,这通常用于数据仓库;它适用于某些类型的问题 - 例如,我将它用于保险系统,其中需要两个日期之间的总天数,以及数据的整体日期范围易于估计(来自最早的客户出生日期为未来几年的日期,超出任何正在出售的保单的结束日期。)

可能不适合你,但我认为值得分享是一种有趣的技巧!

答案 3 :(得分:0)

在您添加示例后,很明显我确实误解了您的问题。

您不是“累积相交的行”。

将为您提供解决方案的步骤是:

将每一行的起点和终点与给定的起点和终点相交。这应该是可以使用CASE表达式或类似的东西,这样的风格:

SELECT(CASE startdate&lt; givenstartdate:givenstartdate,CASE startdate&gt; = givenstartdate:startdate)as retainedstartdate,(同样适用于enddate)as retainedenddate FROM ...根据需要提供nulls和那种东西。

使用retainstartdate和retainedenddate,使用日期函数计算保留间隔的长度(这是您的行与给定时间段的重叠)。

选择那些的SUM()。