【问题标题】:Where ActiveRecord query return empty AssociationRelationActiveRecord 查询返回空的 AssociationRelation
【发布时间】:2018-07-20 17:14:37
【问题描述】:

我想查询将结果添加到数组中,例如:

app/models/user.rb

query = self.patients.where(["created_at >= ? and created_at >= ? and created_at >= ?", Time.zone.now.beginning_of_day, Time.now.beginning_of_week, Time.now.beginning_of_month]).to_a

预期结果:

query
=> [3, 5, 12]

当前结果:

Patient Load (0.8ms)  SELECT `patients`.* FROM `patients` WHERE `patients`.`medic_id` = 1 AND (created_at >= '2018-07-20 00:00:00' and created_at >= '2018-07-16 05:00:00' and created_at >= '2018-07-01 05:00:00')
=> #<ActiveRecord::AssociationRelation []>

without to_a method => [#<ActiveRecord::AssociationRelation []>]
with to_a method => []

型号

class User < ApplicationRecord 
  has_many :patients, dependent: :destroy
end

class Patient < ApplicationRecord
  belongs_to :user
end

我收到一个空数组/AssociationRelation,我怎样才能得到包含一天、一周、一个月开始的患者数量的数组,像这样query = [3, 5, 12]?

注意,使用:

  • Mysql:版本 15.1 Distrib 10.1.34-MariaDB,适用于 Linux (x86_64),使用 读线 5.1
  • 红宝石:2.3.3p222
  • 导轨:5.0.0.1
  • 活动记录:5.0.0.1

【问题讨论】:

  • 这不是 ActiveRecord 的工作方式。你不能用一个select返回这些值,你需要三个子查询。

标签: mysql ruby-on-rails ruby activerecord


【解决方案1】:

解决方案:

class Patient < ApplicationRecord
  scope :created_since, -> (time) { where('created_at >= ?', time) }
  # ...
end

示例:

如何获取包含一天、一周、一个月开始的患者数量的数组,例如这个查询 = [3, 5, 12]?

patients_counts = [
  Patient.created_since(Time.zone.now.beginning_of_day).count,
  Patient.created_since(Time.zone.now.beginning_of_week).count,
  Patient.created_since(Time.zone.now.beginning_of_month).count,
]

puts patients_counts
# => [3, 5, 12]
  • 万一你不知道,你也可以这样做:@user.patients.created_since(...)

附注我不建议在一个查询中进行,而只需像上面那样进行三个单独的计数查询。您可以在一个查询中完成,但您必须编写一个非常具体的 SQL,并且会变得很丑,因为您需要三个子查询(据我所知)。

【讨论】:

  • 为什么不使用一个示波器打发时间?
  • 我认为您可以使用 case 语句处理一个子查询?我通常使用 tsql (sql server),所以我不太确定语法,但类似:"SELECT SUM(q.today) AS today, SUM(q.week) AS week, SUM(q.month) AS month FROM (SELECT CASE WHEN created_at &gt;= ? THEN 1 ELSE 0 END AS today, CASE WHEN created_at &gt;= ? THEN 1 ELSE 0 END AS week, CASE WHEN created_at &gt;= ? THEN 1 ELSE 0 END AS month) AS q"。虽然对于 activerecord 来说这绝对是非常讨厌的,但你也许可以用 arel 对它进行 frankenstein 。
  • 哦,我从来没有想过这样做。有趣......虽然,你不认为这会比计算三个子查询慢吗?我不精通 SQL,但在我看来,CASE WHEN 对每一行都应用了一个逻辑,所以我只是想知道它会使其变慢吗?稍后我会试试你的;我很好奇:D
  • @Jay-ArPolidario 谢谢,它工作得很好,如果我想减少对数据库的查询数量,那么我必须在原始 sql 中进行查询?
  • @Jay-ArPolidario 我不确定。该计数可能会将 sql 查询更改为类似于 SELECT COUNT(id) FROM table WHERE created_at &gt; ? 的东西,我想这会非常快,并且取决于服务器可能可以重新使用三个计数的执行计划。无论哪种方式,我认为您肯定想在 created_at 列上放置一个索引?我很想知道这两种方法之间的一些基准。
【解决方案2】:

另一种解决方案是使用 SQL UNION 运算符组合由不同时间戳过滤的 3 组不同记录。您可以在这篇文章中阅读如何实现这样的结果:ActiveRecord Query Union

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-07-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-08-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多