简体   繁体   English

Rails 查询按单个关联行列对记录进行排序

[英]Rails query to order records by single association row column

Say I have a books table that has id and name columns and a has_many book_ratings association.假设我有一个 books 表,其中包含 id 和 name 列以及 has_many book_ratings 关联。 The book_ratings table has id, rating, rating_date, and book_id columns and belongs_to:book. book_ratings 表有 id、rating、rating_date 和 book_id 列以及 belongs_to:book。 I'm displaying the books in a table with 3 columns: the books name, the highest rating for the book, and the most recent rating for the book.我在一个包含 3 列的表格中显示书籍:书籍名称、书籍的最高评分和书籍的最新评分。 I want each column sortable and I'm using the Pagy gem for pagination.我希望每一列都可以排序,并且我正在使用 Pagy gem 进行分页。 I want to make a single call to each table to avoid N+1.我想对每个表进行一次调用以避免 N+1。

I made this query which includes the max_rating and sorts by max_rating:我做了这个查询,其中包括 max_rating 并按 max_rating 排序:

@pagy, @books = pagy(
  Book.joins(:book_ratings)
      .select('books.*,MAX(rating) as max_rating')
      .order('max_rating')
      .group('books.id')
)

With each book record, I can call book.max_rating to display the max_rating in the table.对于每本书记录,我可以调用 book.max_rating 以在表中显示 max_rating。 I cannot think of a way to also include the rating with the latest date and sort the records by that rating.我想不出一种方法来包含最新日期的评级并按该评级对记录进行排序。 I know I can use MAX(rating_date) to get the date of the book_rating with the most recent date, but I need a way to include the rating value of the book_rating with the latest date and also be able to order the book records by those values.我知道我可以使用MAX(rating_date)来获取最新日期的 book_rating 日期,但我需要一种方法来包含最新日期的 book_rating 的评级值,并且还能够通过那些来订购图书记录值。

Any ideas?有任何想法吗?

To get this to work, I ended up using a select method and then chaining two joins methods.为了让它工作,我最终使用了 select 方法,然后链接了两个连接方法。 Here's what I ended up using:这是我最终使用的:

Book.select('books.*,t2.rating as latest_rating,t4.rating as highest_rating')
    .joins(
      "INNER JOIN (
         SELECT book_ratings.rating, book_ratings.book_id, book_ratings.rating_date
         FROM book_ratings
         JOIN (
           SELECT book_id, MAX(rating_date) as max_date
           FROM book_ratings GROUP BY book_id
         ) t1
         ON t1.book_id = book_ratings.book_id
         AND t1.max_date = book_ratings.rating_date
       ) t2
       ON t2.book_id = books.id"
    )
    .joins(
      "INNER JOIN (
         SELECT book_ratings.rating, book_ratings.book_id
         FROM book_ratings
         JOIN (
           SELECT book_id, MAX(rating) as max_rating
           FROM book_ratings
           GROUP BY book_id
         ) t3
         ON t3.book_id = book_ratings.book_id
         AND t3.max_rating = book_ratings.rating
       ) t4
       ON t4.book_id = books.id"
    )
    .distinct

Calling .to_sql on that query gives this SQL:在该查询上调用.to_sql得到这个 SQL:

SELECT DISTINCT books.*,t2.rating as latest_rating,t4.rating as highest_rating
FROM "books"
INNER JOIN (
  SELECT book_ratings.rating, book_ratings.book_id, book_ratings.date
  FROM book_ratings
  JOIN (
    SELECT book_id, MAX(date) as max_date
    FROM book_ratings
    GROUP BY book_id
  ) t1
  ON t1.book_id = book_ratings.book_id
  AND t1.max_date = book_ratings.date
) t2
ON t2.book_id = books.id
INNER JOIN (
  SELECT book_ratings.rating, book_ratings.book_id
  FROM book_ratings
  JOIN (
    SELECT book_id, MAX(rating) as max_rating
    FROM book_ratings
    GROUP BY book_id
  ) t3
  ON t3.book_id = book_ratings.book_id
  AND t3.max_rating = book_ratings.rating
) t4
ON t4.book_id = books.id

When iterating through this collection, latest_rating and highest_rating can be called on each object and provides the value from the rating column for either.遍历此集合时,可以在每个 object 上调用 latest_rating 和 highest_rating 并提供来自评级列的值。 It can also be used with .order('latest_rating asc') (or desc) or .order('highest_rating asc') (or desc)它也可以与.order('latest_rating asc') (或 desc)或.order('highest_rating asc') (或 desc)一起使用

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM