2010-09-28 32 views
22

我在使用will_paginate時遇到了一些複雜的查詢,無法正確計算總記錄數(爲了顯示正確數量的頁面鏈接) - 即由於按多列分組。如何獲取由ActiveRecord#查找創建的SQL語句而不實際執行?

因此,我打算獲取SELECT查詢,該查詢將用於檢索所有記錄,而不實際執行它,並手動將它與SELECT COUNT(*) FROM ...包裝在一起,以獲取記錄數。

任何想法如何做到這一點?

編輯:我使用Rails 2.3.x版本

+0

的[獲取,將來自特定方法或named_scope執行的SQL](http://stackoverflow.com/questions/974020/get-the-sql-that-可能重複將被執行的某種方法或命名範圍) – 2010-09-29 10:22:47

回答

34

對於Rails的3:

退房在Rails 3 docs ActiveRecord的::關係的文檔。

# 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

謝謝,當我們遷移到3時,我會記住這一點。我忘記提及我們仍在使用2.3.x,抱歉。 – 2010-09-28 16:18:50

+0

它也適用於Rails 4 :) – 2015-09-18 06:50:25

0

前段時間,我爲此使用了一個名爲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\"" 
+0

謝謝,我會試試看。你可能知道它是構建SQL模仿AR行爲還是以某種方式包裝AR?即我可以相信它會給出完全相同的查詢'AR#find'會嗎? – 2010-09-28 18:57:15

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 }),但它有點爲我工作(我只用它在開發雖然,所以我有一些容錯的錯誤)

9

看來,在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 
+1

經過測試,確實可以正常工作。我想我應該接受自己的答案。:/ – 2010-11-20 18:13:50

+0

有沒有辦法添加*:include *以及? – 2017-07-03 18:10:08

0

我知道這個問題詢問「沒有執行它」,但#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)