Domanda

Sto usando PHP Doctrine ORM per creare le mie query. Tuttavia, non riesco proprio a capire come scrivere la seguente clausola WHERE usando DQL (Doctrine Query Language):

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

Come posso specificare dove vanno le parentesi?

Quello che ho attualmente nel mio codice PHP è questo:

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

Ma questo produce qualcosa di simile

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

che, a causa dell'ordine delle operazioni, non restituisce i risultati previsti.

Inoltre, c'è una differenza tra " dove " ;, " eWhere " ;, e " addWhere " metodi?

Aggiorna Ok, sembra che non sia possibile eseguire query complesse utilizzando DQL, quindi ho provato a scrivere SQL manualmente e utilizzare il metodo andWhere () per aggiungerlo. Tuttavia, sto usando WHERE..IN e Doctrine sembra eliminare le mie parentesi racchiuse:

$q->andWhere("(category1 IN $subcategory_in_clause
            OR category2 IN $subcategory_in_clause 
            OR category3 IN $subcategory_in_clause)");
È stato utile?

Soluzione

Dalla mia esperienza, ogni complessa funzione where è raggruppata tra parentesi (sto usando Doctrine 1.2.1).

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

produce il seguente SQL:

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

Altri suggerimenti

Il modo corretto per farlo è disponibile in dottrina 2 - query condizionali del generatore di query ... Se istruzioni? come notato da @Jekis. Ecco come utilizzare il generatore di espressioni per risolvere questo problema come nell'esempio di @ 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);

Dato che non è possibile eseguire query complesse utilizzando DQL, ho scritto il seguente SQL per passare al metodo andWhere ():

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

Nota il " AND TRUE " ;, un hack in modo che il parser non ignori le parentesi esterne.

e Dove si può riassumere come:
Condizioni aggiunte in precedenza Consapevoli dell'istruzione WHERE

Puoi tranquillamente utilizzare e Dove al posto di dove . (introduce un overhead molto piccolo, che è indicato di seguito nella seconda voce dell'elenco.)

L'implementazione di 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);
}

che può essere letto come

  1. Parametri di processo
  2. aggiungi AND all'istruzione dove parte della query, se un'altra istruzione in cui è stata aggiunta prima
  3. aggiungi condizione

Per quanto riguarda la differenza tra where, andwhere e addwhere, non credo che ci sia una differenza significativa dall'ultima volta che ho letto la fonte. Ti incoraggio a leggere la fonte di Dottrina, comunque. È davvero semplice e aiuta a riempire i buchi nella documentazione (ce ne sono molti). Per quanto riguarda le complesse dichiarazioni in cui, me lo sono chiesto da solo, ma non ne ho ancora avuto bisogno.

Nella mia esperienza, a volte ho visto una differenza tra:

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

La prima istruzione è scritta su 3 righe, la seconda su una sola. Non ci credevo ma C'È UNA DIFFERENZA!

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

saresti così gentile da provare questa variante, non sei sicuro che funzioni, ma vale la pena provare

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top