【问题标题】:ActiveRecord: is it possible do a join relation with a scopeActiveRecord:是否可以与范围建立连接关系
【发布时间】:2019-03-10 23:01:58
【问题描述】:

这是我原来的问题。我有两个模型如下。

class Author < ActiveRecord::Base
  has_many :books
end

class Book < ActiveRecord::Base
  belongs_to :author

  scope :available, ->{ where(available: true) }
end

我想离开加入作者到图书的“可用”范围。以下是我想在 DB 上执行的查询。可以这样做吗?

Select authors.* , count(books.*) as books_count 
From authors left outer join books on books.author_id = authors.id 
and books.available = true 
group by (authors.id) order by books_count;

我试过以下方法

 Author.joins("LEFT OUTER JOIN authors on books.author_id = authors.id")
.merge(Book.available)
.select("authors.* , count(books.*) as books_count")
.group("authors.id").order("books_count")

但这会导致以下查询。

Select authors.* , count(books.*) as books_count 
From authors left outer join books on books.author_id = authors.id 
where books.available = true 
group by (authors.id) order by books_count;

所以它会删除所有没有书的作者。

重要提示:我的 AR 版本没有 left_outer_joins 方法

【问题讨论】:

  • 你想要的输出是什么?
  • 查找每个作者的书数(也有没有书的作者)并按书数排序。
  • @ShanakaKuruwita 所以你的意思是它应该包括没有书但books_count应该是0的作者。是吗?
  • @Vishal 完全正确

标签: ruby-on-rails ruby-on-rails-3 activerecord rails-activerecord


【解决方案1】:

您需要再添加一个查询来检查作者是否没有书籍,然后我们需要添加它。请尝试以下查询

 Author.joins("LEFT OUTER JOIN authors on books.author_id = authors.id")
.merge(Book.available)
.where("books.author_id IS NULL")
.select("authors.* , count(books.*) as books_count")
.group("authors.id").order("books_count")

【讨论】:

  • 这似乎是一个不错的方法,但是这个 where 将在 where 子句中添加一个 AND 运算符而不是 OR。所以我最终没有得到任何结果。 'or' 方法在我的版本中不可用。
  • @ShanakaKuruwita or 方法在您的版本中不可用是什么意思?您必须在查询中使用 OR。您是否尝试了上述查询,或者您对现有查询进行了更改?
  • 是的,我尝试了您的确切查询。什么意思是 Model.where.or 这里guides.rubyonrails.org/…
  • @ShanakaKuruwita 但是,当您可以简单地使用or 进行上述查询时,为什么要使用活动记录的or 方法。我认为上述查询将 100% 有效。您不需要查找任何其他活动记录方法
  • 这是我得到的查询:- Select authors.* , count(books.*) as books_count From authors left outer join books on books.author_id = authors.id where ( books.available = true ) AND (books.author_id IS NULL) group by (authors.id) order by books_count;
【解决方案2】:

虽然它不使用您的范围。 (主要是因为您的范围包含一个您不希望作为查询一部分的 where 子句)

您可以使用arel 执行此操作,例如:

book_table = Book.arel_table
author_table = Author.arel_table
author_join = author_table.join(book_table,Arel::Nodes::OuterJoin)
  .on(book_table[:author_id].eq(author_table[:id]).and(
       book_table[:available].eq(true)
    )
  )
Author.joins(author_join.join_sources)
  .select("authors.* , count(books.*) as books_count")
  .group("authors.id").order("books_count")

这将导致以下 SQL:

SELECT 
  authors.* , 
  count(books.*) as books_count
FROM 
  authors 
  LEFT OUTER JOIN books ON books.author_id = authors.id
    AND books.available = true
GROUP BY 
  authors.id
ORDER BY 
  books_count

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-13
    • 2011-06-09
    • 1970-01-01
    • 2023-03-11
    • 1970-01-01
    • 2018-11-25
    相关资源
    最近更新 更多