Reputation: 10296
I have this statement:
myuser.orders.exists?(['(orderstatus = ?) ', statusid])
It returns true since there is an orderstatus that matches the statusid.
Next I have:
myuser.orders.where('id not in (?)', nil).exists?(['(orderstatus = ?) ', statusid])
This returns false where I thought it might return true since there are no ids that are nil.
Then I have:
myuser.orders.where(nil).exists?(['(orderstatus = ?) ', statusid])
This returns true.
My question is why does the middle statement return false? It doesn't complain or throw any errors. I guess I'm using nil wrong, but can someone explain?
Upvotes: 1
Views: 1390
Reputation: 434735
You're having trouble with SQL's NULL. The where
in the middle one:
where('id not in (?)', nil)
becomes this SQL:
id not in (null)
and that's equivalent to this:
id != null
But the result of id != null
is neither true nor false, the result is NULL and NULL in a boolean context is false; in fact, x = null
and x != null
result in NULL for all x
(even when x
itself is NULL); for example, in 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 and every other reasonably compliant database will do the same thing (with possibly different casting requirements to make the NULL obvious).
The result is that where(id not in (?)', nil)
always yields an empty set and your existence check will always fail on an empty set.
If you want to say "all the rows where id
is not NULL" then you want to say:
where('id is not null')
If your id
is a primary key (as it almost certainly is), then id
will never be NULL and you can leave that where
out completely.
When you hand where
just a nil
:
where(nil)
where
's argument parsing logic will ignore the nil
completely and where(nil)
will be the same as where()
and where()
does nothing at all to the query. The result is that the first and third queries are identical as far as the database is concerned.
Upvotes: 4