我正在使用will_paginate
进行一些复杂的查询,并且无法正确计算总记录数(为了显示正确数量的页面链接) - 即因为按多列分组。
因此,我打算获取SELECT查询,该查询将用于检索所有记录,而不实际执行它,并手动用SELECT COUNT(*) FROM ...
包装它,以获取记录数。
任何想法怎么做?
编辑:我正在使用Rails 2.3.x
答案 0 :(得分:42)
对于Rails 3:
查看Rails 3 docs上的ActiveRecord :: Relation文档。
# get the relation
rel = User.complex_scope.chained_complex_scope
# get the SQL
# this does not execute the query
sql = rel.to_sql
# find out how many records
# this executes the query behind the scenes
count = rel.size
答案 1 :(得分:10)
似乎在Rails 2.x中,可以使用一个名为ActiveRecord::Base#construct_finder_sql
的私有方法,我需要对它进行更多测试,看看它是否适用于我:
ActionType.find(:all, :select => 'hosted, top_action_type, count(*) as count', :group => 'hosted, top_action_type').count
#=> 6
sql = ActionType.send :construct_finder_sql, :select => 'hosted, top_action_type, count(*) as count', :group => 'hosted, top_action_type'
#=> "SELECT hosted, top_action_type, count(*) as count FROM "action_types" GROUP BY hosted, top_action_type"
ActionType.count_by_sql "SELECT COUNT(*) FROM (#{sql}) a"
#=> 6
答案 2 :(得分:1)
我知道这个问题并没有执行#34;但是#explain
方法非常有用,至少应该在这里提及。它对于调试慢速查询非常有用。
注意:它确实执行查询。
http://guides.rubyonrails.org/v3.2.8/active_record_querying.html#running-explain
$ User.where("users.email LIKE '%longford%'").explain
User Load (0.6ms) SELECT `users`.* FROM `users` WHERE (users.email LIKE '%longford%')
=> EXPLAIN for: SELECT `users`.* FROM `users` WHERE (users.email LIKE '%gmail%')
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| 1 | SIMPLE | users | ALL | NULL | NULL | NULL | NULL | 5 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
1 row in set (0.00 sec)
答案 3 :(得分:0)
对于Rails 4及更高版本,请使用above中解释的to_sql
。
前段时间,我使用了一个名为sql_display的插件。
>> Post.sql
=> "SELECT * FROM \"posts\""
>> Post.sql(:order => "id DESC")
=> "SELECT * FROM \"posts\" ORDER id DESC"
>> Post.scoped({}).sql
=> "SELECT * FROM \"posts\""
>> Post.count_sql
=> "SELECT count(*) AS count_all FROM \"posts\""
答案 4 :(得分:0)
不幸的是在Rails 2.x中这实际上很难。我之前在Stack Overflow上发布了类似的问题,最后深入研究了Rails的源代码以找到方法。它的构建方式不允许这样做。
我最终做的是在我回滚的事务中运行查询,并且在事务的长度上将记录器设置为我自己可以阅读的StringIO对象。
这是来自记忆,但希望你理解它足以调整它,如果它不起作用:
Model.transaction do
Model.logger = str = StringIO.new
Model.complex_scope.chained_complex_scope
Model.logger = ActiveRecord::Base.logger
str.rewind
str = str.read
# perform some regex on str to get the actual query
raise ActiveRecord::Rollback
end
它很丑陋,我从不喜欢它(我把它包裹在sql { Model. complex_scope.chained_complex_scope }
中)但它对我有用(我只在开发中使用它,所以我对错误有一些容忍度)