Active Record NOT IN查询和MySQL的NULL

时间:2013-09-22 22:36:41

标签: mysql ruby-on-rails ruby-on-rails-3 activerecord rails-activerecord

我有一个类似的查询:

Tag.where('id not IN (?)', current_user.tags.pluck(:id)).uniq

current_user.tags.pluck(:id)).uniq

返回NULL,我没有得到Tag查询的结果,这不是所希望的行为。

我在这里做错了什么?

感谢。

2 个答案:

答案 0 :(得分:3)

我认为current_user.tags.pluck(:id)不会给你一个nil,它会返回一个空数组。在这种情况下ActiveRecord will treat an empty array as a NULL。结果是一些荒谬的SQL,如下所示:

select tags.* from tags where id in (null)

由于SQL的NULL(特别是x = NULLx != NULL的特性对于所有x都是假的),因此in (null)not in (null) WHERE子句不匹配任何内容。

将Ruby的[]转换为NULL的Rails非常愚蠢(关于over here的更多讨论),但即使它足够聪明地引发异常,你仍然需要处理手动使用“空数组”案例,如下所示:

tag_ids = current_user.tags.pluck(:id)
if(tag_ids.empty?)
  tags = Tag.all
else
  tags = Tag.where('id not in (?)', tag_ids)
end

并且您不需要uniq,SQL in运算符会将其RHS视为一组,因此重复项将在幕后折叠。

答案 1 :(得分:1)

在传递的参数为空数组时,使用where.not让Rails处理。

由于 mu太短指出,当传递给查询条件的值是一个空数组时,ActiveRecord会将其转换为NULL,这会打乱您的查询,并将始终返回一个空结果。

处理此问题的旧方法是有条件地检查一个空数组作为参数,而不添加此条件。但是,使用引入了where.not的Rails 4,我们不再需要进行此检查。

我们可以简单地做到:

Tag.where.not( id: current_user.tags.pluck(:id) ).uniq

现在ActiveRecord将自动检查一个空数组,当它看到它时,条件变为1=1,这实际上是没有意义的,但更重要的是,它只会被忽略,其余查询将像该条件从未添加到查询中。