【问题标题】:How to parameterize a date range in a rails (postgres) query?如何在rails(postgres)查询中参数化日期范围?
【发布时间】:2018-08-01 20:05:28
【问题描述】:

正如标题所问,如何在查询中包含日期范围?

例如,假设我有一个名为VisitToGrandma 的模型,它有一个名为visit_date 的字段。现在,我想查找上个月发生的所有对祖母的访问。

这是我正在尝试的:

VisitToGrandma.where("? @> visit_date", (1.month.ago..Time.now))

但是,这会产生查询:

SELECT "visits_to_grandmas".* FROM "visits_to_grandmas" WHERE ('2018-07-01','2018-07-02','2018-07-03','2018-07-04','2018- 07-05','2018-07-06','2018-07-07','2018-07-08','2018-07-09','2018-07-10','2018-07- 11','2018-07-12','2018-07-13','2018-07-14','2018-07-15','2018-07-16','2018-07-17' ,'2018-07-18','2018-07-19','2018-07-20','2018-07-21','2018-07-22','2018-07-23',' 2018-07-24','2018-07-25','2018-07-26','2018-07-27','2018-07-28','2018-07-29','2018- 07-30','2018-07-31','2018-08-01' @> visit_date)

参数化的正确方法是什么?

是的,我知道这个虚构的例子,我可以只使用开始和结束日期并使用BETWEEN 或其他一些运算符来执行此操作,而不使用实际的日期范围,但这不是我想要的询问。

编辑指出这个问题与the other question 有何不同:

这个问题只是关于在一个范围内查找一个日期,我的问题是询问如何实际参数化一个范围对象,以便可以使用所有 postgresql 的日期范围运算符。

【问题讨论】:

  • @jvillian,是的,它们是非常相似的问题,但是那个问题的上下文是“没有结果出现”,而我的上下文是“它正在产生一个不正确的查询”。 ¯\_(ツ)_/¯
  • 认识到上下文的差异,该方法是否适用? VisitToGrandma.where(visit_date: 1.month.ago..Time.now)?
  • @jvillian,对于这个虚构的例子,是的,但我需要知道如何包含日期范围才能使用所有 postgresql 的日期范围运算符,而不仅仅是查找日期是否在此范围内跨度>
  • 为我的困惑道歉,但你的意思是当字段类型是 postgres daterange

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


【解决方案1】:

正如我最近在另一个 PostgreSQL/range/ActiveRecord 回答中提到的,AR 与 PostgreSQL 范围类型的集成是有限的。

您可以通过半手动生成所需范围的字符串表示来解决此问题:

ActiveRecord::Base.connection.type_cast(1.month.ago.to_date .. Time.now.to_date)

不是#to_date 调用来获取日期而不是时间戳。你也可以说:

today = Date.today
ActiveRecord::Base.connection.type_cast(today.months_ago(1) .. today)

将其与您的查询混合:

today = Date.today
VisitToGrandma.where(
  '? @> visit_date',
  VisitToGrandma.connection.type_cast(today.months_ago(1) .. today)
)

根据上下文,您可能更容易/更清晰地访问connection。您可能想要包含一个类型转换,以确保没有任何误解:

today = Date.today
VisitToGrandma.where(
  '?::daterange @> visit_date',
  VisitToGrandma.connection.type_cast(today.months_ago(1) .. today)
)

【讨论】:

  • 使用connection.type_cast 让它很开心。谢谢。 :)
【解决方案2】:

看来您需要滥用一些 where 占位符才能使用 ActiveRecord 完成此操作

VisitToGrandma.where(
  ":range::daterange @> date",
  range: '[2011-01-01,2011-03-01)'
)

注意范围内的符号 [),有关 Postgres 文档的更多信息 https://www.postgresql.org/docs/current/static/rangetypes.html#RANGETYPES-IO

【讨论】:

  • daterange 可用并且我们正在处理日期时,为什么要使用tsrange?您可以使用connection.type_cast 生成适当格式的字符串,#type_cast 还可以正确区分..... 范围。
  • 你是对的@muistooshort,daterange 是比较日期而不是时间戳的正确运算符。我会更新我的答案谢谢。你介意用你的建议发布另一个答案吗?
  • 我认为我现有的答案已经很好地涵盖了它,但请随时更新您的答案。
猜你喜欢
  • 2021-10-08
  • 2012-09-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-09-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多