我想知道如何在数据库中表示一个时间结束(正无穷大)值。
当我们使用32位时间值时,显而易见的答案是实际的32位时间结束 - 接近一年2038。 既然我们使用的是64位时间值,我们无法在DATETIME字段中表示64位结束时间,因为64-bit end of time is billions of years from now。
由于SQL Server和Oracle(我们的两个支持平台)都允许使用多达9999年的数据,因此我认为我们可以选择一些“大”的未来日期,例如1/1/3000。 但是,由于客户和我们的质量保证部门都会查看数据库值,我希望它显而易见,并且看起来不像有人搞砸了他们的日期算术。
我们只是选择约会并坚持下去吗?
答案 0 :(得分:12)
使用最大整理日期,具体取决于您的DBMS,可能是9999-12-31。你想要做到这一点,因为如果你试图像一些评论者所建议的那样使用Null,或者像Marc B所建议的那样使用永久旗帜,那么基于日期范围的查询很快会变得非常复杂。
当您在日期范围内使用最大整理日期表示“永远”或“直到另行通知”时,它会产生非常简单,自然的查询。它使这些查询非常简单明了:
... WHERE effective_date <= @PointInTime AND expiry_date >= @PointInTime
... WHERE effective_date <= @StartOfRange AND expiry_date >= @EndOfRange
... WHERE A.effective_date <= B.expiry_date AND B.effective_date <= A.expiry_date
... WHERE expiry_date = @MaxCollatingDate
使用此方法可能会为某些用户带来一些问题,他们可能会发现“9999-12-31”在报告或屏幕上混淆。如果这对你来说是一个问题,那么drdwicox建议将翻译用于用户友好的价值是好的。但是,我建议用户界面层,而不是中间层,是这样做的地方,因为可能最合理或可口的可能会有所不同,这取决于您是在谈论报告还是数据输入表格和观众是内部还是外部。例如,您可能想要的一些地方是一个简单的空白。其他人你可能想要“永远”这个词。其他人你可能想要一个带有复选框的空文本框,上面写着“直到进一步通知”。
答案 1 :(得分:7)
在PostgreSQL中,the end of time是'无限'。它还支持'-infinity'。 “无限”值保证晚于所有其他时间戳。
create table infinite_time (
ts timestamp primary key
);
insert into infinite_time values
(current_timestamp),
('infinity');
select *
from infinite_time
order by ts;
2011-11-06 08:16:22.078
infinity
至少从版本8.0开始,PostgreSQL支持'infinity'和'-infinity'。
至少可以通过使用dbms支持的最大日期来模仿此行为。但最长日期可能不是最佳选择。 PostgreSQL的最大时间戳是294,276的一段时间,这肯定会让一些人感到惊讶。 (我不喜欢让用户感到惊讶。)
2011-11-06 08:16:21.734
294276-01-01 00:00:00
infinity
这样的值可能更有用:'9999-12-31 11:59:59.999'。
2011-11-06 08:16:21.734
9999-12-31 11:59:59.999
infinity
这不是9999年的最大值,但数字排列很好。您可以将该值包装在infinity()函数和CREATE DOMAIN
语句中。如果您从源代码构建或维护数据库结构,则可以使用宏扩展将INFINITY
扩展为合适的值。
答案 2 :(得分:3)
我们有时会选择一个日期,然后制定一项政策,确保日期不得过滤。执行该策略的最常见位置是中间层。我们只是过滤结果,将“神奇”的结束日期更改为更适合的东西。
答案 3 :(得分:2)
不要让日期变得“特别”。虽然你的代码不太可能在9999左右,甚至在2 ^ 63-1左右,但看看几年前使用'12 / 31/1999'引起的所有乐趣。
如果您需要发出“无限”或“无限”时间的信号,请添加一个布尔/位字段来表示该状态。
答案 4 :(得分:1)
代表“直到永恒”或“直到另行通知”的概念是一个不确定的命题。
关系理论本身说没有null这样的东西,所以你不得不把它分成两部分的表:一部分是已知结束日期/结束时间的行,另一部分是结束时间尚未知晓的行。
但是(就像有一个null)将表分成两部分会使你的查询写得太乱。视图可以在某种程度上适应只读部分,但更新(或在视图上编写INSTEAD OF)将很难,无论如何都可能会对性能产生负面影响。
将null表示“结束时间尚未知晓”将使更新变得有点“更容易”,但读取查询会使您需要的所有CASE ...或COALESCE ...构造变得混乱。
使用dportas提到的理论上正确的解决方案会在您想要从DATETIME“提取”DATE的所有情况下变得混乱。如果手头的DATETIME值是“(可表示的)时间的结束(从现在开始的数十亿年),那么这不仅仅是在DATETIME值上调用DATE提取器函数的简单情况,因为你是也希望DATE提取器为您的案例生成“可表示的DATE结束”。
另外,您可能不希望在用户界面中将“缺席时间结束”显示为值9999-12-31。因此,如果您使用数据库中结束时间的“实际价值”,那么您将面临一些工作,即该值不会在您的UI中出现在任何地方。
很抱歉没能说有办法避开所有混乱。你真正拥有的唯一选择是最终陷入困境。