2010-11-23 79 views
0

我正在改寫幾天前提出的一個問題。 click this看到上一個問題Rails 2.3.8:如何根據字段的最高值選擇記錄?

我已經回答了這個問題,但它是不正確的。

表中的記錄

alt text

Revision.find(:all,:select => "id,name,max(revision) as revision", :conditions => ["saved=1"],:group => 'name') 

這將導致

alt text

其實結果應該是ID 3,6,8。

查詢中的哪些修改將導致此結果?

回答

1

這是SQL不太適合的查詢類型。簡而言之,問題在於,您實際上需要的是組操作,然後在每個組內排序,然後從每個子組中獲取最高記錄。事實證明,這是一個令人驚訝的難題,因爲SQL在排序之前會進行分組。通常,分組是針對彙總數據的,而不是選擇特定的記錄。

有很多SQL特定的方法可以解決這個問題,但它們都不適合Rails。相反,我會組織你的數據,像這樣:

  1. 擁有recipe_revisions模型,其中包括一個完整的配方記錄
  2. 有一個配方模型,這基本上只是ID /名稱/最新版本。
  3. 要獲得配方的當前副本,您需要從配方中選擇所需的配方,然後加入名稱/最大修訂版本的recipe_revisions,其中這些列在兩個表上都編入索引。

這不是容易解決方案,它會運作良好。

0

將查詢拆分爲兩部分。在第一個找到每個名稱的最大修訂版。在第二個查詢中查找與名稱和修訂相匹配的完整行。

CREATE TEMP TABLE max_revisions (name varchar, revision integer); 
INSERT INTO max_revisions SELECT name, max(revision) FROM revisions 
     WHERE saved = 1 GROUP BY name; 
SELECT r.* FROM revisions r INNER JOIN max_revisions m 
     ON m.name = r.name AND m.revision = r.revision; 

現在你的問題可能是,如何在Rails中表達這一點。

您可以使用Revision.connection.execute然後使用Revision.find_by_sql(都包裝在一個方法中,例如:Revision.find_by_max_revisions)。

否則,如果你的數據庫不支持臨時表,或者你只是不想讓他們,你可以讀取max_revisions到內存中,然後用它來構建查詢:

class Revision 
    def self.find_by_max_revisions 
    max_revs = connection.select_values(
     sanitize_sql(
     ["SELECT name, max(revision) as max_rev FROM #{table_name} 
       WHERE saved = ? GROUP BY name", 1] 
    ), "Load max_revisions for #{self.name}" 
    ) 
    max_revs.map do |row| 
     find_by_name_and_revision(row["name"], row["max_rev"].to_i) 
    end 
    end 
end 
0
Revision.find(:all, :select => "DISTINCT id", :conditions => ["saved=1"], :order => 'revision DESC') 
0

我有類似的問題,我還沒有能夠將其轉換爲活動記錄語法,但同事幫助我掀起了一個嵌套選擇,爲我解決了這個問題。事情是這樣的:

select id, name, saved, revision 
from revisions r 
where saved = 1 and 
version_no = (select revision 
       from revisions r2 
       where saved = 1 and r2.name = r.name 
       order by r2.revision desc 
       limit 1 
      ) 

警告:我不知道的性能影響,雖然,我懷疑這是使第二子查詢每一個獨特的修訂場。

相關問題