有条件地排序查询结果

时间:2018-09-20 07:48:48

标签: ruby-on-rails

由于我的最新帖子不是真正的解决方案,因此我不得不重新发布一次:

我的Rails应用中有帖子和评论。我要显示按最近活动排序的帖子,这意味着带有最新评论的帖子排在第一位。

我现在有这个SQL和几个问题:

Post.left_outer_joins(:comments).
order('comments.created_at DESC, posts.created_at DESC').
uniq

如您所见,它连接了两个表,对结果进行排序并从中选择唯一的条目

问题是:

  • 如果帖子没有评论,则这些帖子按照创建时的降序顺序始终显示为第一,但我希望这些帖子按最近活动的顺序进行。

就像一个论坛,可以根据用户最近的活动对用户的帖子进行排序

我想将列comments.created_atposts.created_at合并到列posts.created_at中,其值是:

  • comments.created_at(如果不为null的话)
  • posts.created_at如果没有评论

,然后在posts.created_at

之后对整个查询进行排序

非常感谢您为解决此问题所提供的帮助,谢谢

3 个答案:

答案 0 :(得分:1)

在这种情况下,您可以做的是按两者的最大值进行排序。

Post.left_outer_joins(:comments).
order('GREATEST(comments.created_at, posts.created_at) DESC').
uniq

答案 1 :(得分:0)

我只是在Ruby中做过

@posts = Post.where(category: params[:category])
@posts.each do |p|
  p.created_at = p.comments.count == 0 ? p.created_at : p.comments.last.created_at
end
@posts = @posts.sort_by { |k| k[:created_at] }.reverse
@posts = @posts.paginate(page: params[:page])

答案 2 :(得分:0)

app / models / post.rb

class Post < ApplicationRecord
  has_many :comments
end

app / models / comment.rb

class Comment < ApplicationRecord
  belongs_to :post
end

db / schema.rb

ActiveRecord::Schema.define(version: 2018_09_20_081230) do

  create_table "comments", force: :cascade do |t|
    t.text "comment_content"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.integer "post_id"
  end

  create_table "posts", force: :cascade do |t|
    t.string "post_title"
    t.text "post_content"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
  end

end

查询

Post.includes(:comments).order('comments.created_at DESC')

测试环境:

  • Ruby 2.3.5

  • Ruby 5.2.1

更新

Post.joins('LEFT JOIN comments ON comments.post_id = posts.id').group('posts.id').order('COALESCE(MAX(comments.created_at), posts.created_at) DESC')

Post.find_by_sql('SELECT posts.* FROM posts LEFT JOIN comments ON comments.post_id = posts.id GROUP BY posts.id ORDER BY COALESCE(MAX(comments.created_at), posts.created_at) DESC')