sql - Rails - 在日期可选时存储日期

标签 sql ruby-on-rails postgresql activerecord ruby-on-rails-5

我正在收集一个日期以存储在数据库中,但必须考虑到用户可能不知道确切日期这一事实。我想提供仅输入月份和年份的选项。将这些值存储在数据库中的最佳方式是什么?

如果我使用不带日期的 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_startpossible_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)(范围在其末端隐式排他)。

http://rextester.com/AWIO2403

关于sql - Rails - 在日期可选时存储日期,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43066932/

相关文章:

postgresql - 当我使用 "sslmode=verify-full"时,连接到 Azure 上的 postgres 服务器失败

python - Django:通过通用关系过滤 order_by

php - 需要一个mysql查询来解决 "group by"和 "order by"不返回最新消息

SQL:根据财务报告的最后付款日期创建账龄桶

javascript - 方法错误,没有为用户拉取GPS坐标

ruby-on-rails - webrick Rails 服务器启动后几秒钟关闭

postgresql - 为什么我的 LEFT JOIN 在我执行 "SELECT * "时有效,但在我仅选择必要的列时失败?

mysql重命名数据库不起作用

php - 从 MySQL 列获取唯一值

ruby-on-rails - Netbeans 可以用作 Sinatra 的 IDE 吗?