Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/ruby-on-rails/64.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql Rails通过关联查询限制到最近的记录?_Sql_Ruby On Rails_Ruby - Fatal编程技术网

Sql Rails通过关联查询限制到最近的记录?

Sql Rails通过关联查询限制到最近的记录?,sql,ruby-on-rails,ruby,Sql,Ruby On Rails,Ruby,我需要一个返回以下内容的查询: 最近一本书有:complete=>true的用户。i、 e.如果用户的最新书籍有:complete=>false,则我不希望它们出现在我的结果中 到目前为止我所拥有的 class User has_many :books 这是一个有希望的开始,但没有给我我需要的结果。我已尝试添加一个.order(“在描述上创建”).limit(1) 在上面的查询结束时,我只得到一个结果,而我期望得到很多结果 谢谢 您应该在这里使用范围-它们将使您的生活变得更加简单(这是一个r

我需要一个返回以下内容的查询:

最近一本书有:complete=>true的用户。i、 e.如果用户的最新书籍有:complete=>false,则我不希望它们出现在我的结果中

到目前为止我所拥有的

class User 
has_many :books
这是一个有希望的开始,但没有给我我需要的结果。我已尝试添加一个
.order(“在描述上创建”).limit(1)

在上面的查询结束时,我只得到一个结果,而我期望得到很多结果


谢谢

您应该在这里使用范围-它们将使您的生活变得更加简单(这是一个rails3示例)

在您的book.rb模型中

User.joins(:books).merge(Book.where(:complete => true))

然后你可以调用
User.books.recent.completed
来获取你想要的内容

我想不出一个简单的查询方法,但你可以:

scope :completed, where("complete = ?", true)
scope :recent, order("created_on ASC")

如果您不打算使用@rubyprince的ruby解决方案,那么这实际上是一个比ActiveRecord以最简单的形式处理更复杂的DB查询,因为它需要一个子查询。下面是我如何完全通过一个查询来实现这一点:

User.all.select { |user| user.books.order("created_at desc").limit(1).complete }
要将其转换为ActiveRecord,我将执行以下操作:

SELECT   users.*
FROM     users
         INNER JOIN books on books.user_id = users.id
WHERE    books.created_on = ( SELECT  MAX(books.created_on)
                              FROM    books
                              WHERE   books.user_id = users.id)
         AND books.complete = true
GROUP BY users.id
class User
  scope :last_book_completed, joins(:books)
    .where('books.created_on = (SELECT MAX(books.created_on) FROM books WHERE books.user_id = users.id)')
    .where('books.complete = true')
    .group('users.id')
end
然后,通过执行以下操作,您可以获得拥有上一本已完成书籍的所有用户的列表:

SELECT   users.*
FROM     users
         INNER JOIN books on books.user_id = users.id
WHERE    books.created_on = ( SELECT  MAX(books.created_on)
                              FROM    books
                              WHERE   books.user_id = users.id)
         AND books.complete = true
GROUP BY users.id
class User
  scope :last_book_completed, joins(:books)
    .where('books.created_on = (SELECT MAX(books.created_on) FROM books WHERE books.user_id = users.id)')
    .where('books.complete = true')
    .group('users.id')
end

我最近遇到了一个类似的问题,下面是我如何解决它的:

User.last_book_completed

通过这种方式,我们只使用ActiveRecord方法(没有额外的SQL),并且在为用户考虑任何书籍子集(first、last、LastN books等)时可以重用它。您需要最后一个“uniq”,否则每个用户都会出现两次。

这会增加一点开销,但会节省复杂性,并在以后重要的时候提高速度

在书籍中添加“最近”栏。确保添加索引

most_recent_book_ids = User.all.map {|user| user.books.last.id }
results = User.joins(:books).where('books.id in (?) AND books.complete == ?', most_recent_book_ids, true).uniq
基于左联接而不是内部联接,并且没有分组:

User.last_book_completed
范围:随着最后一本书的完成,->{
子查询=书本。选择(:id)
.where(“books.user\u id=users.id”)
.订单(在::desc.创建)。限制(1)

加入(对。正在尝试检查:complete=>true?仅针对每个用户的最新图书记录,但显然不起作用…抛出错误:未定义的方法“books”for#--我需要针对所有用户进行查询,而不是instance@john..you无法在用户模型上调用
.books
。您只能在类似
@User的实例上调用它=User.first
@rubyprince是的,完全正确。您不能。这将不满足OP的标准:“如果用户最近的书有:complete=>false,我不希望它们出现在我的结果中。”这就是我最终实现的,但我觉得必须有一种更干净的方法来实现db查询。对我来说,这就像是一个简单的请求……我想投票给你,但没有代表:/I know man,我的解决方案非常糟糕,并生成(n+1)查询。但当时我找不到更好的解决方案。这就是为什么我要求@pan看一看这个问题,他确实给出了一个漂亮而正确的答案。这产生了N+1问题,实际上你不想在你的应用程序中使用。我收到了一个sqlite语法错误“大约‘已完成’”当我尝试此操作时。看起来很有希望!哦,您可能已经将变量命名为“complete”而不是“completed”。只需更改变量名称。我更新了答案以使用complete而不是completed。@pan..条件
'books.complete=true'应该是
'books.complete=1'`还是
'books.complete=?',true
,如果我这是一个常量,不是用户输入,没有必要用'books.complete=?'对其进行清理,true.1或true应该也能工作,至少在MySQL中是这样。这是迄今为止最巧妙的回答,但必须添加一些东西来将现有的图书记录标记为最新的(如果数据库已经有一些值)。
User.last_book_completed
scope :with_last_book_complete, -> {
  subquery = Book.select(:id)
                 .where("books.user_id = users.id")
                 .order(created_at: :desc).limit(1)

  joins(<<-SQL).where(books: { complete: true })
    LEFT JOIN books
      ON books.user_id = users.id
      AND books.id = (#{subquery.to_sql})
  SQL
}