2010-05-05 112 views
4

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

我想查询具有两个开始和停止日期时间的所有行的交集的持续时间。

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

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


举个例子,使用毫秒这样可以很清楚:

的某些行:

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

而且我们想知道的总和时,这些行分别为1030和1100之间。

允许计算各行的重叠:

ROW INTERSECTION 
1 70 
2 10 
3  0 

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

+3

我很难理解你的问题。你能否举例说明一下。 – lexu 2010-05-05 07:30:45

+0

像1-10,2-9,3-8这样的重叠的总和是多少? – aioobe 2010-05-05 07:39:56

+0

@Will - 如果我正确读了你的话,你在示例#1中的交集不应该是30;交叉点((1010,1240),(1030,1100))= 70 – Unreason 2010-05-05 08:46:56

回答

5

如果你的榜样应该说70的第一行中,然后

假设@range_start和@range_end作为你的条件paramters:使用greatest /最少,date functions你应该能够

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

得到你需要的日期类型直接操作。

1

我担心你的运气不好。

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

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

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

或者我误解了你的问题。

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之间的总运行时间毫秒数。

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

正如我所说,这通常用于数据仓库;它非常适合于某些类型的问题 - 例如,我已经将它用于保险系统,其中需要两个日期之间的总天数,并且数据的整个日期范围很容易估算(来自最早的出生日期至未来几年的日期,超过任何正在出售的政策的结束日期。)

可能不适合你,但我想它值得作为一种有趣的技术分享!

0

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

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

,将带给你一个解决方案的步骤是:

相交的每一行的起点和终点与给定的起点和终点。

SELECT(CASE STARTDATE < givenstartdate:givenstartdate,CASE STARTDATE> = givenstartdate:开始日期)为retainedstartdate,(同样为结束日期),其retainedenddate这应该使用的样式CASE表达式或自然的东西,什么是可行FROM ...根据需要照顾nulls和那种东西。

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

选择这些的SUM()。