Сложные предложения WHERE с использованием ORM доктрины PHP

Я использую ORM PHP Doctrine для построения своих запросов. Однако я не совсем понимаю, как написать следующее предложение WHERE с использованием DQL (Doctrine Query Language):

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

person Wickethewok    schedule 26.06.2009    source источник
comment
Другое решение можно найти здесь stackoverflow.com/a/7720723/251735   -  person Jekis    schedule 03.12.2013


Ответы (7)


По моему опыту, каждая сложная функция 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
person anushr    schedule 11.01.2010
comment
Именно то, что я искал! - person Rico Humme; 01.07.2015

Правильный способ сделать это можно найти в doctrine 2 - условные запросы построителя запросов ... Если операторы?, как заметил @Jekis. Вот как использовать построитель выражений для решения этой проблемы, как в примере @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);
person David Baucum    schedule 18.08.2016
comment
Именно поэтому я ненавижу Доктрину. Это невозможно прочитать и понять. - person Nicolas; 05.12.2016
comment
вы также можете сделать это так: $ ors = $ qb- ›expr () -› orX (); $ ors- ›add ($ qb-› expr () - ›like ('firstName', $ qb-› expr () - ›literal (% john%))); $ ors- ›add ($ qb-› expr () - ›like ('lastName', $ qb-› expr () - ›literal (% john%))); $ qb- ›andWhere ($ ors); - person Nuryagdy Mustapayev; 25.04.2020
comment
Или вы можете просто пропустить весь этот шум и объединить строку DQL ... Просто убедитесь, что вы не открываете себя для SQL-инъекции. - person Jacob Thomason; 09.11.2020

Поскольку кажется, что вы не можете выполнять сложные запросы с использованием DQL, я написал следующий SQL для передачи методу andWhere ():

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

Обратите внимание на «И ИСТИНА», хитрость, чтобы синтаксический анализатор не игнорировал внешние скобки.

person Wickethewok    schedule 26.06.2009
comment
Я думаю, что решение anushr намного лучше. Никакого взлома и использования подготовленных заявлений. - person Petr Peller; 15.12.2010

andWhere можно резюмировать как:
Ранее добавленные условия с учетом утверждения WHERE

Вы можете безопасно использовать andWhere вместо where. (это приводит к очень крошечным накладным расходам, которые указаны ниже во втором элементе списка.)

Реализация andWhere: (Доктрина 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, если перед этим был добавлен другой оператор where
  3. добавить условие
person Lashae    schedule 05.02.2011

Что касается разницы между where, andwhere и addwhere, я не верю, что есть существенная разница по сравнению с последним разом, когда я читал источник. Однако я бы посоветовал вам прочитать исходный текст Доктрины. Это действительно просто и помогает заполнить пробелы в документации (их много). Что касается сложных операторов where, я сам задавался вопросом, но пока в этом не нуждался.

person Bob Gettys    schedule 26.06.2009

По своему опыту я иногда видел разницу между:

$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-х строчках, второе - только на одной. Я не поверила, но ЕСТЬ РАЗНИЦА!

person baboush    schedule 05.03.2014

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

Не могли бы вы попробовать этот вариант, не уверен, что он работает, но стоит попробовать

person T. Kelher    schedule 15.05.2019