【问题标题】:Rails query: Where association is the parent's first associated record?Rails 查询:父级的第一个关联记录在哪里关联?
【发布时间】:2017-03-23 15:33:09
【问题描述】:

我有一份有很多发票的工作,一张发票属于一个工作。我想查询其第一张发票落在某个日期范围内的作业。我有这个查询:

@jobs = Job.joins(:invoices).
  where("invoices.date BETWEEN ? AND ?", @from_date, @to_date).
  where("invoices = job.invoices.first")

第二个 where 子句是伪代码,但它让您了解我想要做什么。

如果重要的话,我正在使用 MYSQL。

【问题讨论】:

  • 作用域的好用!!

标签: mysql ruby-on-rails activerecord


【解决方案1】:

我的查询是:

@jobs = Job.where("
  id IN (
    SELECT T1.job_id
    FROM invoices as T1 JOIN (
      SELECT job_id, MIN(id) AS first_id
      FROM invoices
      GROUP BY job_id
    ) as T0 ON T1.id = T0.first_id
    WHERE T1.date > ? AND T1.date < ?
  )
", @from_date, @to_date)

解释:

  • T0 包含 job_id 第一个按 job_id 分组的发票 id
  • T1 是 INVOICE 表将在 first_id 上与 T0 连接,因此只会选择第一张发票,然后使用给定的日期范围进行过滤
  • Job.where在子查询中查询job的id

【讨论】:

  • 谢谢!这是有道理的!非常感谢!
  • 只是它的语法无效。我没有时间调试,请参阅我的答案以获得更简单的面向 Rails 的解决方案。
  • 仔细检查你的解决方案,has_one不代表第一张发票,生成的joins查询会和has_many一样!
  • 这确实意味着您订购时创建的第一张发票。
  • 刚才说了,你会仔细检查! eg:在这里阅读生成的查询Job.joins(:first_invoice).to_sql,你就会知道我说了什么
【解决方案2】:

使用 Rails 最简单的方法是添加一个范围,如下所示:

has_one  :first_invoice, -> { order('created_at DESC')  }, class_name: 'Invoice'

那么你可以这样做:

@jobs = Job.joins(:first_invoice).where("invoices.date BETWEEN ? AND ?", @from_date, @to_date)

编辑 - 这实际上不起作用。第一个发票范围适用于作业实例以获取其第一张发票,但在加入时不起作用。

【讨论】:

    【解决方案3】:

    另一种方法 - 您可以向 Job 添加一列并存储 first_invoice_date(并对其进行索引)。查询、排序、合并范围、显示首张发票日期等变得容易得多。

    【讨论】:

    • 固体溶液。我可能最终会这样做。谢谢!
    猜你喜欢
    • 1970-01-01
    • 2016-01-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多