0

我在一系列带有各种相关表的 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 的 a 的时间段。在没有重叠的地方很容易获得记录:

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 将 a 分成两个记录呢?将日期范围显示为时间线,我如何获得如下所示c的关系(这些线表示表和中的各个记录的日期范围,以及结果集)a-b=cabc

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

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

4

2 回答 2

2

几个指针:

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

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

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

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

  • 您也可以考虑使用.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 中完成该部分。

于 2013-09-10T18:06:29.050 回答
0

使用.NET 的时间段库,您可以将时间段读入集合并应用TimeGapCalculatorTimePeriodCombinerTimePeriodSubtractor实用程序来评估所需的间隙和重叠。

于 2013-09-13T13:18:07.297 回答