这个ActiveRecord'where'子句如何工作?

时间:2012-05-16 01:22:37

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

我有这样的声明:

myuser.orders.exists?(['(orderstatus = ?) ', statusid])

它返回true,因为有一个与statusid匹配的orderstatus。

接下来我有:

myuser.orders.where('id not in (?)', nil).exists?(['(orderstatus = ?) ', statusid])

这会返回false,我认为它可能会返回true,因为没有id为nil。

然后我有:

myuser.orders.where(nil).exists?(['(orderstatus = ?) ', statusid])

返回true。

我的问题是为什么中间语句会返回false?它不会抱怨或抛出任何错误。我想我使用的是nil错误,但有人可以解释一下吗?

1 个答案:

答案 0 :(得分:4)

你遇到SQL的NULL问题。中间的where

where('id not in (?)', nil)

成为这个SQL:

id not in (null)

这相当于:

id != null

但是id != null的结果既不是真也不是假,结果是NULL并且布尔上下文中的NULL为false;事实上,x = nullx != null导致所有x为NULL(即使x本身为NULL);例如,在PostgreSQL中:

=> select coalesce((11 = null)::text, '-NULL-');
 coalesce 
----------
 -NULL-
(1 row)

=> select coalesce((11 != null)::text, '-NULL-');
 coalesce 
----------
 -NULL-
(1 row)

=> select coalesce((null = null)::text, '-NULL-');
 coalesce 
----------
 -NULL-
(1 row)

=> select coalesce((null != null)::text, '-NULL-');
 coalesce 
----------
 -NULL-
(1 row)

MySQL和其他所有合理兼容的数据库都会做同样的事情(可能有不同的转换要求,以使NULL显而易见)。

结果是where(id not in (?)', nil)总是产生一个空集,并且您的存在检查将始终在空集上失败。

如果你想说“id不是NULL的所有行”,那么你想说:

where('id is not null')

如果您的id是主键(几乎可以肯定),那么id永远不会为NULL,您可以完全保留where


当您where时只需nil

where(nil)

where的参数解析逻辑将完全忽略nil,而where(nil)将与where()相同而where()对此无效查询。结果是,就数据库而言,第一个和第三个查询是相同的。