【问题标题】:Date range set operations日期范围设置操作
【发布时间】:2013-09-10 17:35:24
【问题描述】:

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

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

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

【问题讨论】:

  • 尝试过这样的事情:WHERE condition BETWEEN lower_range AND upper_range
  • SQL:2011 看起来很有希望。也许我只需要复习一下我的 C 语言,然后自己将其中一些功能添加到 SQLite 中。

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


【解决方案1】:

几点建议:

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

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

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

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

  • 您也可以考虑使用Time Period Library for .NET,它定义了大量 数量的操作。请注意,与它一起使用的所有DateTime 值都具有DateTimeKind.Utc.Kind 值。如果您尝试使用本地种类,它将无法正常运行。也就是说,不要传DateTime.Now

  • 当然,没有必要使用 any 库。您始终可以定义自己的结构或类来包含范围。没有为此内置任何东西,没有。

  • 您编写的查询非常适合检测重叠,但您可能需要稍微简化一下:

    而不是这个:NOT(a.start > b.end OR b.start > a.end)
    这样做:a.start < b.end AND b.start < a.end

    这在逻辑上是等效的,但作为查询的性能会稍好一些。

我不确定如何直接回答您的问题。目前还不太清楚你在问什么。具体来说,在最后一个示例中,c 的两个范围是否已经存在于表中并且您想要返回它们?或者您想构造它们从 a 和 b 之间的计算?如果是后者,最好在 C# 中而不是在 SQL 中完成该部分。

【讨论】:

  • “我如何在 a-b=c 中获得 c(两条记录)”我的意思是如何从 a 和 b 构造 c。对于 a 和 b 之间的任意关系,我如何进行查询以查找不与 b 相交的 a 的日期范围。当我说“两条记录”时,我的意思是 c 可以表示两条或更少的记录,具体取决于 b 是否包含在 a 中、与 a 部分重叠或完全覆盖 a。
  • 您可以在您的 C# 代码中构造c。我不会在 SQL 中尝试这样做。但是对于查询,输入参数是什么?您想要所有个没有重叠的日期范围吗?或者你是在传递一个日期还是一个开始和结束日期?
  • 我在这里寻找一般案例。换句话说,在我的输入数据中,a 可能代表一个或多个不相交的日期范围,而 b 可能代表零个或多个不相交的日期范围。我想找到零个或多个不相交的范围 c,它是通过删除 a 和 b 之间的所有重叠范围而产生的。
  • 但是范围肯定仍然受到一些最短开始日期和最长结束日期的限制,是吗?否则,您必须检索数据库中的所有数据才能执行此操作 - 我猜这很多。
  • 嗯...如果我正在构建查询以回答的问题是“在 A 中查找在 B 中没有相关记录的所有记录”,那么我猜时间约束将是最大值和最小值A 中记录的日期?我不确定这有什么关系,但这有帮助吗?就像我说的那样,我正在寻找一般情况。这不适用于单个查询或操作。我需要从这些数据中回答许多不同的问题,有些是特定于时间点的(很容易编写查询),有些是特定时间间隔的,有些是一般性的,适用于所有/任何时间。跨度>
【解决方案2】:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-04-12
    • 2018-05-25
    • 1970-01-01
    • 1970-01-01
    • 2022-01-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多