Pregunta

Estoy usando PHP Doctrine ORM para construir mis consultas. Sin embargo, parece que no puedo entender cómo escribir la siguiente cláusula WHERE usando DQL (Doctrine Query Language):

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

¿Cómo puedo especificar dónde van los paréntesis?

Lo que tengo actualmente en mi código PHP es esto:

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

Pero esto produce algo así como

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

que, debido al orden de las operaciones, no devuelve los resultados previstos.

Además, ¿hay alguna diferencia entre " donde " ;, " yWhere " ;, y " addWhere " métodos?

ACTUALIZACIÓN Ok, parece que no puedes hacer consultas complejas usando DQL, así que he estado tratando de escribir el SQL manualmente y usar el método andWhere () para agregarlo. Sin embargo, estoy usando WHERE..IN y Doctrine parece estar eliminando mis paréntesis adjuntos:

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

Solución

Desde mi experiencia, cada función compleja where se agrupa entre paréntesis (estoy usando Doctrine 1.2.1).

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

produce el siguiente SQL:

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

Otros consejos

La forma correcta de hacerlo se puede encontrar en doctrina 2 - consultas condicionales del generador de consultas ... Si las declaraciones? como lo señaló @Jekis. Aquí se explica cómo usar el generador de expresiones para resolver esto, como en el ejemplo de @ 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);

Como parece que no puedes hacer consultas complejas usando DQL, escribí el siguiente SQL para pasar al método andWhere ():

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

Tenga en cuenta el " AND TRUE " ;, un truco para que el analizador no ignore los paréntesis externos.

yDónde se puede resumir como:
Condición (es) añadida (s) anteriormente (s) conscientes de la declaración WHERE

Puede usar con seguridad yWhere en lugar de where . (presenta una sobrecarga muy pequeña, que se indica a continuación en el segundo elemento de la lista).

La implementación de andWhere is: (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);
}

que se puede leer como,

  1. Parámetros de proceso
  2. agregue la instrucción AND a where parte de la consulta, si se agregó otra instrucción where antes
  3. agregar condición

En cuanto a la diferencia entre where, andwhere y addwhere, no creo que haya una diferencia significativa desde la última vez que leí la fuente. Sin embargo, le animo a leer la fuente de Doctrina. Es realmente simple y ayuda a llenar los agujeros en la documentación (hay muchos). En cuanto a las declaraciones complejas de where, me lo he preguntado yo mismo, pero aún no lo he necesitado.

En mi experiencia, a veces he visto una diferencia entre:

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

y

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

La primera declaración está escrita en 3 líneas, la segunda, en una sola. ¡No lo creía pero HAY UNA DIFERENCIA!

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

¿sería tan amable de probar esta variante, no estoy seguro si funciona, pero vale la pena intentarlo?

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top