存储日期时间的首选方式

Jul*_*ian 24 database-design datetime

我们可以通过多种方式存储日期和时间信息。存储 DateTime 信息的最佳方法是什么?

使用 DateTime将日期和时间存储在2 个单独的列一列中

你能解释为什么这种方法更好吗?

(链接到 MySQL 文档以供参考,问题是一般性的,不是特定于 MySQL)
日期和时间类型:日期和时间

Han*_*non 25

将数据存储在单列中是首选方式,因为它们是密不可分的。一个时间点是一条信息,而不是两条信息。

许多产品在“幕后”使用的一种存储日期/时间数据的常用方法是将其转换为十进制值,其中“日期”是十进制值的整数部分,“时间”是小数部分价值。因此,1900-01-01 00:00:00 存储为 0.0,2016 年 9 月 20 日 9:34:00 存储为 42631.39861。42631 是自 1900-01-01 以来的天数。.39861 是自午夜以来经过的时间部分。不要直接使用十进制类型来做到这一点,使用明确的日期/时间类型;我的观点只是一个例子。

将数据存储在两个单独的列中意味着您需要在任何时候想要查看给定时间点是早于还是晚于存储值时组合两个列值。

如果单独存储这些值,您将不可避免地遇到难以检测的“错误”。以以下为例:

IF OBJECT_ID('tempdb..#DT') IS NOT NULL
DROP TABLE #DT;
CREATE TABLE #DT
(
    dt_value DATETIME NOT NULL
    , d_value DATE NOT NULL
    , t_value TIME(0) NOT NULL
);


DECLARE @d DATETIME = '2016-09-20 09:34:00';

INSERT INTO #DT (dt_value, d_value, t_value)
SELECT @d, CONVERT(DATE, @d), CONVERT(TIME(0), @d);

SET @d = '2016-09-20 11:34:00';

INSERT INTO #DT (dt_value, d_value, t_value)
SELECT @d, CONVERT(DATE, @d), CONVERT(TIME(0), @d);

/* show all rows with a date after 2016-07-01 11:00 am */
SELECT *
FROM #DT dt
WHERE dt.dt_value >= '2016-07-01 11:00:00';

/* show all rows with a date after 2016-07-01 11:00 am */
SELECT *
FROM #DT dt
WHERE dt.d_value >= CONVERT(DATE, '2016-07-01')
    AND dt.t_value >= CONVERT(TIME(0), '11:00:00');
Run Code Online (Sandbox Code Playgroud)

在上面的代码中,我们创建了一个测试表,用两个值填充它,然后对该数据执行一个简单的查询。第一个SELECT返回两行,但是第二个SELECT只返回一行,这可能不是预期的结果:

在此处输入图片说明

正如@ypercube 在评论中指出的,过滤日期/时间范围(其中值位于离散列中)的正确方法是:

WHERE dt.d_value > CONVERT(DATE, '2016-07-01') /* note there is no time component here */
    OR (
        dt.d_value = CONVERT(DATE, '2016-07-01') 
        AND dt.t_value >= CONVERT(TIME(0), '11:00:00')
    )
Run Code Online (Sandbox Code Playgroud)

如果您需要将时间分量分开以进行分析,您可以考虑为值的时间部分添加一个计算的、持久的列:

ALTER TABLE #DT
ADD dt_value_time AS CONVERT(TIME(0), dt_value) PERSISTED;

SELECT *
FROM #dt;
Run Code Online (Sandbox Code Playgroud)

在此处输入图片说明

然后可以对持久列进行索引,以便按时间进行快速排序等。

如果您正在考虑将日期和时间拆分为两个字段以进行显示,您应该意识到应该在客户端而不是服务器上进行格式化。


JBe*_*ley 11

我将对其他答案提出不同意见。

如果同时需要日期和时间组件,即如果一个条目包含一个但不包含另一个(或一个为 NULL 而另一个不为 NULL),则将其存储在单个列中是有意义的,原因是其他答案。

然而,可能存在一种或两种组件是单独可选的情况。在这种情况下,将其存储在单个列中是不正确的。这样做会迫使您以任意方式表示 NULL 值,例如将时间存储为 00:00:00。

下面是几个例子:

  • 您正在记录车辆行程以减免里程税。知道旅程的确切时间会很有用,但如果员工没有记下并忘记了,日期仍应自行记录(所需日期,可选时间)。

  • 您正在进行一项调查,以了解人们什么时候吃午餐,并要求参与者填写一份包含午餐时间样本的表格,包括日期。有些人不会费心填写日期,并且您不想丢弃数据,因为这是您真正关心的时间(可选日期,所需时间)。

有关替代方法,请参阅此相关问题


Ash*_*han 5

除非有一些特定的业务/应用程序需求,否则我总是更喜欢将它存储为单个列。以下是我的观点——

  • 从时间戳中提取时间不是问题
  • 如果我们可以将两者存储在一起,为什么要为时间添加额外的列
  • 避免每次查询时都添加日期和时间。