我正在收集一个日期以存储在数据库中,但必须考虑到用户可能不知道确切日期这一事实。我想提供仅输入月份和年份的选项。将这些值存储在数据库中的最佳方式是什么?
如果我使用不带日期的 Date 对象,然后将其作为日期存储在数据库中,那么它默认为该月的 1 日,这是不准确的。我的想法可能是将日、月和年分别存储为整数,然后在模型上使用一个方法返回 Date 对象以及日期是否准确(即由用户输入,而不仅仅是默认值)系统)。
虽然看起来有点乱,有没有更好的方法来做到这一点?
谢谢。
最佳答案
有多种解决方案可用。选择最适合您的用例的一种:
<强>1。单独的日期部分字段
您已经尝试过这个想法。好像是这样的:
create table t(
year int,
month int,
day int
)
2017-03
的一个月可以用 (2017, 3, NULL)
表示。
请注意,所有字段都可以NULL
。如果你至少想要一些信息,你可以让 year NOT NULL
。
使用此模型,您必须使用客户端逻辑来构造某种类似日期的对象以供进一步使用。
此模型的一大缺点是难以索引。你可以索引 f.ex。 make_date(year, coalesce(month, 1), coalesce(day, 1))
但在查询中使用它很不方便。此外,要禁止某些毫无意义的值组合(例如给定一年零一天,而不是一个月),您还应该添加一个(非常长的)CHECK
约束,f .ex.
CHECK (CASE
WHEN year IS NULL THEN month IS NULL AND day IS NULL
ELSE CASE WHEN month IS NULL THEN day IS NULL END
END)
<强>2。采样日期和精度
create table t(
sample_date date,
sample_precision date_precision -- enum of f.ex. 'year', 'month', 'day'
)
2017-03
中的一个月可以用 ('2017-03-28', 'month')
表示。
这不需要很长的 CHECK
约束,但是如果 sample_date
真的只是一个样本(f.ex. 当整个2017-03
月份应该在一行中表示,示例日期甚至可以是 2017-03-28
)。当您将第一个日期用作 sample_date
(根据它可以采用的值,基于 sample_precision
),事情会变得稍微容易一些。但是为了完整性需要以下 CHECK
约束:
CHECK (date_trunc(sample_precision::text, sample_date)::date = sample_date)
(稍后会进一步改进这一点。)
<强>3。可能的范围
您可以存储一个可能的日期范围。使用 possible_start
和 possible_end
或使用 PostgreSQL 的 daterange
type .
create table t(
possible_start date,
possible_end date,
-- or
possible_range daterange
)
2017-03
的一个月可以用 ('2017-03-01', '2017-03-31')
表示。
在此模型中,当 possible_start = possible_end
时,date
值是准确的。你现在可以查询两个不同的东西:
- 确定在给定日期附近发生的行(包含)
- 哪些行可能发生在给定日期前后(相交)
这两种类型的查询都可以使用带有 daterange
的索引。
这样做的好处在于您不受月份范围的限制。您可以使用任何长度的范围。它唯一的缺点是范围必须是连续的。
<强>2。 + 3. ?
有一个变体,具有3.的所有优点,但看起来像2.,带有interval
type。 :
create table t(
possible_start date,
possible_length interval day
)
2017-03
中的一个月可以用 ('2017-03-01', '1 month')
表示。
(day
限定符将 interval
的最小精度限制为一天。timestamp
或 不需要它timestamptz
基于解决方案。)
最后可能的日期可以用 (possible_start + possible_length - interval '1 day')::date
表示。或者,整个范围为(对于 daterange
索引):daterange(possible_start, (possible_start + possible_length)::date)
(范围在其末端隐式排他)。
关于sql - Rails - 在日期可选时存储日期,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43066932/