日期范围设置操作

时间:2013-09-10 17:35:25

标签: c# sql sqlite date system.data.sqlite

我在一系列带有各种相关表的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分成两个记录呢?将日期范围显示为时间轴,如何在下面显示的c关系中获得a-b=c(这些行代表表ab中各个记录的日期范围,以及结果集c

a: |-----------------|    |--------|  |--------||-----|
b:        |---|                  |--------|
c: |-----|     |-----|    |-----|          |---||-----|

或者更好的是,是否有一些我不知道的库,扩展,命令,或其他可用于简化这些查询的解决方案?能为我处理凌乱日期范围操作的东西吗?

2 个答案:

答案 0 :(得分:2)

有几点指示:

  • 确保您的值是基于UTC的时间戳,或仅是整个日历日期。这是为了避免时区和夏令时问题。

  • 使用半开区间[start, end)。这将避免两个相邻范围包含相同值的问题。换句话说:

    • start <= value < end
    • start <= value && end > value

  • 您可以考虑使用Noda Time。它有一个Interval类型,可以很好地代表它。但是,它目前没有定义很多操作。

  • 您可能还会考虑使用Time Period Library for .NET,其中定义了大量个操作。请注意,您使用的所有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中执行。

答案 1 :(得分:0)

使用Time Period Library for .NET,您可以将时间段读入集合并应用 TimeGapCalculator TimePeriodCombiner TimePeriodSubtractor 实用程序评估所需的差距和重叠。