在 Doctrine 2 DQL 中结合 IS NULL 和 :value

Combine IS NULL and :value in Doctrine 2 DQL

由于其他(旧)问题没有得到正确的答案,我会再试一次:

我经常遇到这样一种情况,我想查询具有特定值的实体:

$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);      
}

虽然我理解 SQL / DQL 中 NULL != NULL 背后的基本原理,但事实是,在这种情况下,后果真的很烦人。

此外,较旧问题中给出的示例在 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)

当参数可以为 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));

如果 $parentnull,它将自动 special-case SQL 条件为“parent IS NULL”(否则基本条件“parent = ?" + 参数).

否则,在 :parent 上添加条件以避免在组合查询中出现 NonUniqueResult 异常:

SELECT e 
FROM Entity e 
WHERE (e.parent = :parent OR (e.parent IS NULL AND :parent IS NULL))

甚至(直接从您的 "hack" 翻译):

WHERE ((:parent IS NULL AND e.parent IS NULL) OR (:parent IS NOT NULL AND e.parent = :parent))

旁注 关于 "NULL != NULL in SQL / DQL":

严格来说,"NULL = NULL" 和 "NULL != NULL" 既不是 TRUE 也不是 FALSE:两者都是 return NULL。
现在,NULL 不是 "truthy",所以两个查询
SELECT e FROM Entity e WHERE e.parent = NULL”和
SELECT e FROM Entity e WHERE e.parent != NULL
永远不会 return 任何行(对于任何数据),
但是 NULL 也不是 "falsy"(它是第三种,比如说 "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)
也不会 return 任何行!
因此需要使用运算符“x IS NULL”和“x IS NOT NULL”(或“NOT (x IS NULL)”)或COALESCE(),或vendor-specific函数,如[=26] =]、IFNULL()NVL()
(备注:在某些情况下 "undefinedness" 会自动解决,例如在条件
(产生 NULL 的表达式) OR (计算结果为 TRUE 的表达式)”或
(产生 NULL 的表达式) AND (计算结果为 FALSE 的表达式)
因为“anything OR TRUE”始终为 TRUE,而“anything AND FALSE”始终为 FALSE。)