NOT IN组合的表示

时间:2012-12-20 17:28:42

标签: ruby-on-rails ruby arel squeel

我想使用squeel来构建如下的查询:

SELECT * from `table`
WHERE (`field1`, `field2`)
NOT IN (
  (1,"value_a"),
  (2,"value_b"),
  (3,"value_a"),
  ...
)

我想知道是否有任何方法可以通过INNOT IN语句将多个字段与数组进行比较。

这样的事情(我知道这个例子不起作用)是表达我的意思的好方法:

array = [[1,"value_a"], [2,"value_b"], [3, "value_a"]]
Table.where{ (field1 & filed2).not_in array }

这样的事情是否可能?

更新

我知道如何使用多个... & (a != b) & (c != d) & ...获得相同的最终结果,但这不是我所要求的。

2 个答案:

答案 0 :(得分:1)

也许这样?

Product.where{
  (title != 'foo') & (description != 'bar') |
  (title != 'baz') & (description != 'xyz')
}

更新

如果您已经有一个要排除值的数组,您可以创建一个这样的范围:

scope :without_title_and_description, lambda{|array| 
  where{array.map{|c1,c2| (title != c1) & (description != c2)}.inject(:|)} 
}

并使用它:

array = [[1,"value_a"], [2,"value_b"], [3, "value_a"]]
Product.without_title_and_description(array)

产地:

  Product Load (1.0ms)  SELECT "products".* FROM "products" WHERE (((("products"
."title" != 1 AND "products"."description" != 'value_a') OR ("products"."title"
!= 2 AND "products"."description" != 'value_b')) OR ("products"."title" != 3 AND
 "products"."description" != 'value_a')))

答案 1 :(得分:0)

主要问题是,虽然Arel(以及Squeel)支持一些相当复杂的查询,但不包括这种级别的查询复杂性。考虑到这一点,恢复到SQL并手动构建所需的查询是唯一的解决方案,而不是使用此功能扩展Arel本身。

existing_compound_ids = [[1,"value_a"],[2,"value_b"],[3, "value_a"]]

compound_collection = existing_compound_ids.inject([]) do |aftermath, member|
  aftermath << "('#{ member[0] }','#{ member[1] }')"
end.join(",")

Table.where("(`tables`.`field1`, `tables`.field2) NOT IN (#{compound_collection})")

将构造以下SQL:

SELECT `tables`.* from `tables` WHERE ((field1, field2)
NOT IN (('1','value_a'),('2','value_b'),('3','value_a')))

我希望看到更好,更优雅的解决方案,但我还没找到。