Как работает это предложение «где» ActiveRecord?

У меня есть это утверждение:

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

Он возвращает true, так как существует статус заказа, соответствующий статусу.

Далее у меня есть:

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

Это возвращает ложь, где я думал, что она может вернуть истину, поскольку нет нулевых идентификаторов.

Тогда у меня есть:

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

Это возвращает истину.

Мой вопрос: почему средний оператор возвращает false? Он не жалуется и не выдает никаких ошибок. Думаю, я неправильно использую nil, но может кто-нибудь объяснить?


person dtc    schedule 16.05.2012    source источник
comment
Посмотрите в своем журнале запрос, сгенерированный вторым оператором. Если в нем нет объяснения вашего вопроса, также опубликуйте его здесь.   -  person Michael Berkowski    schedule 16.05.2012


Ответы (1)


У вас проблемы с SQL NULL. where в середине:

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

становится этот SQL:

id not in (null)

и это эквивалентно этому:

id != null

Но результат id != null не является ни истинным, ни ложным, результатом является NULL, а NULL в логическом контексте является ложным; на самом деле x = null и x != null приводят к NULL для всех x (даже если 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() вообще ничего не сделает с запросом. В результате первый и третий запросы идентичны с точки зрения базы данных.

person mu is too short    schedule 16.05.2012
comment
Спасибо, это имеет смысл. Спасибо за ясное объяснение. - person dtc; 16.05.2012