多AND/OR运算符SQL转Doctrine DQL的正确性验证求助
你的DQL查询与原SQL不一致,问题及修正方案如下
首先看你的原SQL逻辑:
SELECT * FROM table -- [other WHERE CONDITIONS] WHERE (field-A = 2 AND field-B IS NULL) OR (field-A = 2 AND field-B IS NULL);
这个条件其实等价于 field-A = 2 AND field-B IS NULL(两个完全相同的条件用OR连接没有实际意义),但先分析你写的QueryBuilder代码存在的问题:
现有代码的问题
- 方法调用错误:
isNull('t.field-A')没有调用QueryBuilder的实例方法,正确写法应为$qb->isNull('t.field-A') - 逻辑分组错误:你当前的链式写法未给AND条件添加分组括号,Doctrine会按运算符优先级(AND > OR)拼接逻辑,最终生成的DQL是:
这和原SQL逻辑完全不符——原SQL是两个相同的t.field-A IS NULL AND t.field-B = :data OR t.field-A = :data AND t.field-B IS NULL(field-A=2 AND field-B IS NULL)用OR连接,而你的代码实际表达的是**(field-A为空且field-B等于data) 或者 (field-A等于data且field-B为空)**。
正确的QueryBuilder写法
如果你确实需要原SQL的逻辑(重复OR条件,可简化)
$qb = $this->createQueryBuilder('t'); // 先添加其他WHERE条件 // ... // 简化后的条件(等价于原SQL的重复OR逻辑) $qb->andWhere('t.field-A = :data AND t.field-B IS NULL') ->setParameter('data', $data);
如果是笔误,实际想表达两个不同的组合条件(比如(field-A=:data AND field-B IS NULL) OR (field-A IS NULL AND field-B=:data))
可以用子QueryBuilder的表达式API明确分组条件:
$qb = $this->createQueryBuilder('t'); // 先添加其他WHERE条件 // ... $qb->andWhere(function ($subQb) use ($data) { // 第一个分组条件:field-A等于data 且 field-B为空 $condition1 = $subQb->expr()->andX( $subQb->expr()->eq('t.field-A', ':data'), $subQb->expr()->isNull('t.field-B') ); // 第二个分组条件:field-A为空 且 field-B等于data $condition2 = $subQb->expr()->andX( $subQb->expr()->isNull('t.field-A'), $subQb->expr()->eq('t.field-B', ':data') ); // 用OR连接两个分组条件 $subQb->where($subQb->expr()->orX($condition1, $condition2)); $subQb->setParameter('data', $data); });
或者用更直观的字符串写法(注意手动添加分组括号):
$qb = $this->createQueryBuilder('t'); // 先添加其他WHERE条件 // ... $qb->andWhere('(t.field-A = :data AND t.field-B IS NULL) OR (t.field-A IS NULL AND t.field-B = :data)') ->setParameter('data', $data);
内容的提问来源于stack exchange,提问作者Flys
相关产品推荐
相关产品推荐

