2011-03-14 46 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 
相关问题