2011-03-14 20 views
10

比方說,我們有以下幾點:有沒有辦法反轉ActiveRecord :: Relation查詢?

irb> Post.where(:hidden => true).to_sql 
=> "SELECT `posts`.* FROM `posts` WHERE posts.hidden = 1" 

難道我們某種方式得到一個倒置的SQL查詢出來的嗎?

我所尋找的,或許應該是這樣的:

irb> Post.where(:hidden => true).invert.to_sql 
=> "SELECT `posts`.* FROM `posts` WHERE NOT (posts.hidden = 1)" 
+1

其中(:隱藏=>假) – jenjenut233 2011-03-14 19:15:07

+6

嗯。對某人發表的評論「where(:hidden => false)」讚不絕口。該代碼將*不*生成OP正在查找的SQL類型。 – Zabba 2011-03-14 19:43:07

回答

16

隨着不同的語法,是的。例如:

posts = Post.scoped.table # or Arel::Table.new("posts") 
posts.where(posts[:hidden].eq(true).not).to_sql 
# => SELECT FROM `posts` WHERE NOT ((`posts`.`hidden` = 1)) 
+0

不是我正在尋找的東西,但仍然是一個非常好的答案。 – Kostas 2011-03-15 16:45:28

+0

你有沒有找到另一種方式來做到這一點?也許更好的語法?答案是否適合你? – Zabba 2011-11-03 02:46:04

+0

其實我覺得這是不可能的,因爲我實際上要求的是反轉和ActiveRecord :: Relation對象,它可能會或可能不會有多個連接,並且會包含會使事情複雜化太多的問題(哪些問題應該反轉,哪些不反應? )。我想我會保持開放直到答案出現。 – Kostas 2011-11-03 09:30:06

5

我們可以通過將倒置的查詢回的ActiveRecord採取Zabba's answer進一步:

table = Post.arel_table 
query = table[:hidden].eq(true).not # the inverted query, still ARel 
Post.where(query) # plug it back into ActiveRecord 

這將返回ActiveRecord對象,因爲你通常會期望。

0

當我在尋找記錄了「不正確」的條件(例如,虛假或無)是我做什麼:

Post.where(["(hidden IS NULL) OR (hidden = ?)", false]) 
-1

對於單表查詢,這會工作:

query = Post.where(hidden:true) 
inverse = Post.where('id not in (?)', query.pluck(:id)) 

當然,我們會遇到可怕的效率問題,並且它不會生成您要求的SQL查詢(儘管運行時它最終會生成相同的結果集)。

+0

實際上,如果你使用'select'而不是'pluck',這將不會那麼糟糕,因爲那樣它將嵌套查詢而不是創建一個id數組的Ruby數組。 – Ritchie 2015-01-14 06:09:31

5

在軌道4有此目的not後綴:

Post.where.not(hidden: true).to_sql 
# => SELECT FROM `posts` WHERE `posts`.`hidden` != 1 

在軌道3,你可以使用squeel gem。它提供了許多有用的功能。有了它,你可以寫:

Post.where{ hidden != true }.to_sql 
# => SELECT FROM `posts` WHERE `posts`.`hidden` != 1 
相關問題