使用PHP Doctrine ORM的复杂WHERE子句

时间:2009-06-26 15:04:31

标签: php mysql doctrine dql

我正在使用PHP Doctrine ORM构建我的查询。但是,我似乎无法想象如何使用DQL(Doctrine查询语言)编写以下WHERE子句:

WHERE name='ABC' AND (category1 = 'X' OR category2 = 'X' OR category3 = 'X') 
AND price > 10

如何指定括号的位置?

我目前在PHP代码中拥有的是:

->where('name = ?', 'ABC')
->andWhere('category1 = ?', 'X')
->orWhere('category2 = ?', 'X')
->orWhere('category3 = ?', 'X')
->andWhere('price > ?', 10)

但这会产生类似

的东西
WHERE name='ABC' AND category1 = 'X' OR category2 = 'X' OR category3 = 'X' 
AND price > 10

,由于操作顺序,不会返回预期的结果。

此外,“where”,“andWhere”和“addWhere”方法之间是否存在差异?

更新 好吧,看起来你不能使用DQL进行复杂的查询,所以我一直在尝试手动编写SQL并使用andWhere()方法来添加它。但是,我正在使用WHERE..IN而且Doctrine似乎正在剥离我的括号:

$q->andWhere("(category1 IN $subcategory_in_clause
            OR category2 IN $subcategory_in_clause 
            OR category3 IN $subcategory_in_clause)");

7 个答案:

答案 0 :(得分:68)

根据我的经验,每个复杂的where函数都在括号内分组(我使用的是Doctrine 1.2.1)。

$q->where('name = ?', 'ABC')
  ->andWhere('category1 = ? OR category2 = ? OR category3 = ?', array('X', 'X', 'X'))
  ->andWhere('price < ?', 10)

生成以下SQL:

WHERE name = 'ABC' 
  AND (category1 = 'X' OR category2 = 'X' OR category3 = 'X')
  AND price < 10

答案 1 :(得分:15)

正如@Jekis所指出的那样,可以在doctrine 2 - query builder conditional queries... If statements?找到正确的方法。以下是如何使用表达式构建器来解决这个问题,就像在@ anushr的例子中一样。

$qb->where($qb->expr()->eq('name', ':name'))
  ->andWhere(
    $qb->expr()->orX(
      $qb->expr()->eq('category1', ':category1'),
      $qb->expr()->eq('category2', ':category2'),
      $qb->expr()->eq('category3', ':category3')
  )
  ->andWhere($qb->expr()->lt('price', ':price')
  ->setParameter('name', 'ABC')
  ->setParameter('category1', 'X')
  ->setParameter('category2', 'X')
  ->setParameter('category3', 'X')
  ->setParameter('price', 10);

答案 2 :(得分:1)

由于您似乎无法使用DQL执行复杂查询,因此我编写了以下SQL以传递给andWhere()方法:

$q->andWhere("(category1 IN $subcategory_in_clause
OR category2 IN $subcategory_in_clause 
OR category3 IN $subcategory_in_clause) AND TRUE");

注意“AND TRUE”,一个hack,以便解析器不会忽略外括号。

答案 3 :(得分:1)

并且可以概括为:
以前添加的条件意识到WHERE声明

您可以安全地使用取代 。 (它引入了一个非常小的开销,下面在第二个列表项中说明。)

andWhere的实施是:( Doctrine 1.2.3)

public function andWhere($where, $params = array())
{
    if (is_array($params)) {
        $this->_params['where'] = array_merge($this->_params['where'], $params);
    } else {
        $this->_params['where'][] = $params;
    }

    if ($this->_hasDqlQueryPart('where')) {
        $this->_addDqlQueryPart('where', 'AND', true);
    }

    return $this->_addDqlQueryPart('where', $where, true);
}

可以读作,

  1. 流程参数
  2. AND 语句附加到其中部分查询如果之前添加了另一个where语句
  3. 追加条件

答案 4 :(得分:0)

至于where,wherewhere和addwhere之间的区别,我不相信与上次阅读源代码有显着差异。但是,我鼓励你阅读Doctrine来源。它非常简单,有助于填补文档中的漏洞(有很多)。至于复杂的陈述,我自己也想知道,但还没有需要它。

答案 5 :(得分:0)

根据我的经验,我有时会看到以下区别:

$q->andWhere("(category1 IN $subcategory_in_clause
            OR category2 IN $subcategory_in_clause 
            OR category3 IN $subcategory_in_clause)");

$q->andWhere("(category1 IN $subcategory_in_clause OR category2 IN $subcategory_in_clause OR category3 IN $subcategory_in_clause)");

第一个语句写在3行,第二个只写一行。我不相信,但有一点不同!

答案 6 :(得分:0)

$q->andWhere("category1 IN ( $subcategory_in_clause )
              OR category2 IN ( $subcategory_in_clause )
              OR category3 IN ( $subcategory_in_clause )");

您是否愿意尝试此变体,不确定它是否可行,但是值得一试