Поскольку другие (старые) вопросы не получили правильных ответов, я попробую еще раз:
Я регулярно сталкиваюсь со сценарием, где я хочу запросить объект с определенным значением:
$query = $em->createQuery('SELECT e FROM Entity e WHERE e.parent = :parent');
$query->setParameter('parent', $parent);
Часто это значение может быть NULL, но WHERE e.parent = NULL
не дает результатов, заставляя меня взломать, как это:
if ($parent === null) {
$query = $em->createQuery('SELECT e FROM Entity e WHERE e.parent IS NULL');
}
else {
$query = $em->createQuery('SELECT e FROM Entity e WHERE e.parent = :parent');
$query->setParameter('parent', $parent);
}
Хотя я понимаю обоснование NULL! = NULL в SQL / DQL, на самом деле последствия действительно раздражают в этом случае.
Кроме того, пример, приведенный в предыдущем вопросе, не работает в DQL, для NULL! = NULL.
->setParameter('parent', (is_null($parent) ? "NULL" : $parent));
Я также попробовал этот способ, что любезно предложено, но это даст исключение NonUniqueResult, потому что когда parent равен 1, например, это даст двойной результат.
SELECT e
FROM Entity e
WHERE (e.parent = :parent OR e.parent IS NULL)
Есть ли более чистый способ выполнить этот запрос, когда параметр может быть нулевым?
Если вы не уверены в значении параметра, вы можете переписать предложение where как
SELECT e
FROM Entity e
WHERE (e.parent = :parent OR e.parent IS NULL)
Если у вас есть дополнительные фильтры для вашего запроса, то обязательно используйте ()
вокруг вашего OR
критерии как
SELECT e
FROM Entity e
WHERE (e.parent = :parent OR e.parent IS NULL)
AND e.some = :some...
Если ваш сценарий действительно такой простой и вы просто хотите получить сущности (и на самом деле не заботитесь о запросе), то вместо DQL вы можете использовать функцию репозитория:
$entities = $em->getRepository('Entity')->findBy(array('parent' => $parent));
который автоматически устанавливает особый случай условия SQL какparent IS NULL
» если $parent
является null
(иначе основное условие «parent = ?
«+ параметр).
В противном случае добавьте условие на :parent
чтобы избежать исключения NonUniqueResult в комбинированном запросе:
SELECT e
FROM Entity e
WHERE (e.parent = :parent OR (e.parent IS NULL AND :parent IS NULL))
или даже (в прямом переводе с вашего «хака»):
WHERE ((:parent IS NULL AND e.parent IS NULL) OR (:parent IS NOT NULL AND e.parent = :parent))
Примечание о «NULL! = NULL в SQL / DQL»:
Строго говоря, «NULL = NULL» и «NULL! = NULL» не являются ни ИСТИННЫМИ, ни ЛОЖНЫМИ: оба возвращают NULL.
Теперь NULL не является «правдивым», поэтому оба запроса
«SELECT e FROM Entity e WHERE e.parent = NULL
» а также
«SELECT e FROM Entity e WHERE e.parent != NULL
«
никогда не вернет ни одной строки (для любых данных),
но NULL также не является «ложным» (это третий тип, скажем, «undefined»), и отрицание этого не меняет это: «NOT (NULL)» по-прежнему NULL (и не TRUE), поэтому
«SELECT e FROM Entity e WHERE NOT (e.parent = NULL)
» а также
«SELECT e FROM Entity e WHERE NOT (e.parent != NULL)
«
никогда не вернет ни одной строки!
Отсюда необходимость использования операторов »x IS NULL
» а также «x IS NOT NULL
» (или же «NOT (x IS NULL)
«) или же COALESCE()
или специфичные для поставщика функции, такие как ISNULL()
, IFNULL()
, NVL()
, так далее.
(Примечание: могут быть случаи, когда «неопределенность» решается автоматически, например, в условиях
«(выражение, которое дает NULL) ИЛИ ЖЕ (выражение, которое оценивается как ИСТИНА)» или же
«(выражение, которое дает NULL) А ТАКЖЕ (выражение, которое оценивается как ЛОЖЬ)«
так как «что-нибудь ИЛИ ИСТИНА «всегда ИСТИНА и»что-нибудь И ЛОЖЬ «всегда ЛОЖЬ.)