Pergunta

Eu estou usando o PHP Doutrina ORM para construir minhas consultas. No entanto, eu não consigo parecem figura como escrever a seguinte cláusula WHERE usando DQL (Doutrina Query Language):

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

Como posso especificar onde os parênteses ir?

O que eu tenho atualmente no meu código PHP é esta:

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

Mas isso produz algo como

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

que, por ordem de operações, não retorna os resultados pretendidos.

Além disso, existe uma diferença entre o "onde", "andWhere", e "addWhere" métodos?

Atualizar Ok, parece que você não pode fazer consultas complexas usando DQL, então eu tenho tentado escrever o SQL manualmente e usar o método andWhere () para adicioná-lo. No entanto, estou usando WHERE..IN e Doutrina parece estar tirando as minhas parênteses envolventes:

$q->andWhere("(category1 IN $subcategory_in_clause
            OR category2 IN $subcategory_in_clause 
            OR category3 IN $subcategory_in_clause)");
Foi útil?

Solução

Da minha experiência, cada função where complexo é agrupado entre parênteses (estou usando Doutrina 1.2.1).

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

produz o seguinte SQL:

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

Outras dicas

A maneira correta de fazer isso podem ser encontradas em doutrina 2 - query Builder condicional consultas ... Se declarações como observado por @Jekis?. Aqui está como usar o construtor de expressão para resolver este como em @ de anushr exemplo.

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

Como parece que você não pode fazer consultas complexas usando DQL, escrevi o seguinte SQL para passar para o andWhere () método:

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

Observe o "E VERDADEIRO", um hack para que o analisador não ignoraria os parênteses externos.

andWhere pode ser resumido como:
Anteriormente Adicionado Condição (s) Ciente WHERE

Você pode usar com segurança andWhere inplace de onde . (Ele introduz uma muito pequena sobrecarga, o que é indicado abaixo no 2º item da lista.)

A implementação de andWhere é: (Doutrina 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);
}

que pode ser lido como,

  1. Os parâmetros do processo
  2. append e para , onde parte da consulta, se outro onde declaração foi adicionado antes
  3. condição de acréscimo

Como para a diferença entre onde, andwhere e addwhere, eu não acredito que há uma diferença significativa a partir da última vez que li a fonte. Gostaria de incentivar você a ler a fonte Doutrina, no entanto. É realmente simples, e ajuda preenche os buracos na documentação (há muitos). Quanto complexo onde declarações, eu perguntei isso a mim mesmo, mas não tiveram uma necessidade para ela ainda.

Na minha experiência, tenho visto às vezes uma diferença entre:

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

e

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

A primeira declaração é escrito em 3 linhas, o segundo, em apenas um. Eu não acredito nisso, mas HÁ UMA DIFERENÇA!

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

Você seria tão amável para tentar esta variante, não tenho certeza se ele funciona, mas vale a pena um tiro

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top