Группируйте по столбцам, ограничивайте результат и сортируйте по другим столбцам.

#sql #ruby-on-rails #ruby

Вопрос:

Допустим, у нас есть модели ItemStatistic и Book . ItemStatistic пример записи:

 item_id: 15,  book_id: 3,  score: 0.25192368e4,  

Пример книги:

 id: 3,  title: 'Harry Potter',  

Нам нужно сгруппировать ItemStatistic записи по item_id , затем упорядочить результаты для каждого item_id ключа по score и ограничить количество значений для каждого item_id ключа по 3 и возвращать не ItemStatistic записи, а Book . Пример:

 {15: [{id: 3, title: 'Harry Potter'}, {id: 4, title: 'The Chronicles of Narnia'},...], 2: [...]}  

или

 {1: [{},{},{}], 2: [{},{},{}], 3:[{},{},{}]}  

Ответ №1:

Если я правильно понимаю желание, должно сработать следующее

 item_statistics_table = ItemStatistic.arel_table  filter = Arel::Table.new('filtered_results') sub_query = item_statistics_table.project(  item_statistics[Arel.star],  Arel.sql('ROW_NUMBER() OVER(  PARTITION BY item_statistics.item_id   ORDER BY item_statistics.score DESC  )').as('row_num') )  query = Arel::Nodes::As.new(sub_query, Arel.sql(filter.name))  join_clause = Arel::Nodes::InnerJoin.new(  query,  Arel::Nodes::On.new(  Book.arel_table[:id].eq(filter[:book_id])  .and(filter[:row_num].lteq(3))  )  )  Book  .select(Book.arel_table[Arel.star],filter[:item_id])  .joins(join_clause)  .group_by(amp;:item_id)  

Это должно привести к следующему SQL:

 SELECT   books.*,  filtered_results.item_id FROM   books   INNER JOIN (  SELECT   item_statistics.*,  ROW_NUMBER() OVER(  PARTITION BY item_statistics.item_id   ORDER BY item_statistics.score DESC  ) as row_number  FROM   item_statistics  ) AS filtered_results ON books.id = filtered_results.book_id   AND filtered_results.row_number lt;= 3  

Затем мы группируем все книги по item_id (виртуальному атрибуту), чтобы результат был

 {1 =gt; [Book,Book,Book], 2 =gt; [Book,Book,Book]}  

Результирующий размер массива должен быть