[英]Date range set operations
我在一系列带有各种相关表的SQLite数据库中获得了一些数据。 每个表都有一个开始和结束日期列,表示每个记录有效的日期范围。 SQLite数据库主要使用C#和System.Data.SQLite库进行访问。
我希望能够查询诸如日期范围重叠或不重叠的联接。 我发现加入数据时它们的重叠非常简单:
SELECT a.field, max(a.start, b.start) as start, min(a.end, b.end) as end
FROM a
INNER JOIN b
ON a.field = b.field AND NOT(a.start > b.end OR b.start > a.end);
但我不知道如何获得没有匹配b的时间段。 在没有重叠的地方获取记录很容易:
SELECT a.field, a.start, a.end
FROM a
LEFT JOIN b
ON a.field = b.field AND NOT(a.start > b.end OR b.start > a.end)
WHERE b.field is NULL;
但是它们重叠的位置,或者b分成两个记录呢? 将日期范围显示为时间轴,如何在下面显示的ab=c
关系中得到c
(这些行代表表a
和b
中各个记录的日期范围,以及结果集c
)
a: |-----------------| |--------| |--------||-----|
b: |---| |--------|
c: |-----| |-----| |-----| |---||-----|
或者更好的是,是否有一些我不知道的库,扩展,命令,或其他可用于简化这些查询的解决方案? 能为我处理凌乱日期范围操作的东西吗?
几个指针:
确保您的值是基于UTC的时间戳,或仅是整个日历日期。 这是为了避免时区和夏令时问题。
使用半开间隔, [start, end)
。 这将避免两个相邻范围包含相同值的问题。 换一种说法:
start <= value < end
start <= value && end > value
您可以考虑使用Noda Time 。 它有一个代表这个井的Interval
类型。 但是,它目前没有定义很多操作。
您还可以考虑使用.NET时间段库 ,它定义了大量操作。 请注意,与其.Kind
使用的所有DateTime
值都具有DateTimeKind.Utc
作为其.Kind
值。 如果您尝试使用本地种类,它将无法正常运行。 换句话说,不要传递DateTime.Now
。
当然,没有必要使用任何库。 您始终可以定义自己的结构或类来包含范围。 没有内置任何东西,没有。
您编写的查询适用于检测重叠,但您可能希望稍微简化它:
而不是: NOT(a.start > b.end OR b.start > a.end)
这样做: a.start < b.end AND b.start < a.end
这在逻辑上是等价的,但作为查询会稍微好一点。
我不知道如何直接回答你的问题。 你问的问题并不十分清楚。 具体来说,在最后一个例子中,表中是否已存在两个c
范围并且您想要返回它们? 或者你想从a和b之间的计算中构造它们? 如果是后者,最好在C#中执行该部分,而不是在SQL中执行。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.