Active Record NOT IN查询,对于MySQL为NULL

问题描述 投票:4回答:2

我有一个类似的查询:

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

何时

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

返回NULL,我没有从Tag查询中得到任何结果,这不是期望的行为。

我在这里做错了什么?

谢谢。

mysql ruby-on-rails ruby-on-rails-3 activerecord rails-activerecord
2个回答
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均为假),WHERE子句中的in (null)not in (null)不会匹配任何内容。

[将Ruby的[]转换为NULL的过程非常愚蠢(关于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视为一个集合,因此重复项将被隐藏在后台。


0
投票

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

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

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

我们可以简单地做:

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

现在ActiveRecord将自动检查一个空数组,当它看到它时,条件变为1=1,这本质上是没有意义的,但更重要的是,它将被忽略,并且您的其余查询将像该条件被执行一样运行从未添加到查询中。

© www.soinside.com 2019 - 2024. All rights reserved.