Сложное предложение WHERE с Zend_Db с использованием нескольких операторов AND OR

Я хочу сгенерировать это сложное предложение WHERE в Zend_Db:

SELECT * 
FROM 'products' 
WHERE 
    status = 'active' 
    AND 
    (
        attribute = 'one' 
        OR 
        attribute = 'two' 
        OR 
        [...]
    )
;

Я пробовал это:

$select->from('product');
$select->where('status = ?', $status);
$select->where('attribute = ?', $a1);
$select->orWhere('attribute = ?', $a2);

и это произвело:

SELECT `product`.* 
FROM `product` 
WHERE 
    (status = 'active') 
    AND 
    (attribute = 'one') 
    OR 
    (attribute = 'two')
;

Я выяснил один способ выполнения этой работы, но я чувствовал, что это своего рода "обман", используя PHP, чтобы сначала объединить предложения "ИЛИ", а затем объединить их, используя предложение Zend_Db where(). PHP-код:

$WHERE = array();
foreach($attributes as $a):
    #WHERE[] = "attribute = '" . $a . "'";
endforeach;
$WHERE = implode(' OR ', $WHERE);

$select->from('product');
$select->where('status = ?', $status);
$select->where($WHERE);

Это создало то, что я искал. Но мне любопытно, есть ли "официальный" способ получить этот сложный оператор WHERE (который действительно не слишком сложный, просто добавляя некоторые скобки) с использованием инструмента Zend_Db, вместо того, чтобы сначала комбинировать его в PHP.

Ура!

Ответы

Ответ 1

Это был бы "официальный" способ получить скобки как указано (см. пример № 20 в Zend_Db_Select):

$a1 = 'one';
$a2 = 'two';
$select->from('product');
$select->where('status = ?', $status);
$select->where("attribute = $a1 OR attribute = $a2");

Итак, то, что вы делаете, кажется разумным, учитывая, что вы не знаете, сколько атрибутов у вас есть раньше времени.

Ответ 2

Если вы используете выбранный ответ, вам нужно будет запомнить значения перед построением запроса для защиты от SQL-инъекции.

Другой вариант, который использует Zend Db Select для создания запроса, а также цитирует значения, должен был сделать это в 2 этапа:

/// we just use this select to create the "or wheres"
$select1->from('product');
foreach($attributes as $key => $a) {
    if ($key == 0) {
    /// we don't want "OR" for first one
        $select1->where("attribute = ?", $a);
    } else {
        $select1->orWhere("attribute = ?", $a);
    }   
}

/// now we construct main query
$select2->from('product');
$select2->where('status = ?', $status);
$select2->where(implode(' ', $select1->getPart('where')));

Таким образом Zend Db Select выполняет все генерирование SQL. Старый вопрос, но, надеюсь, эта идея может быть полезной для кого-то с аналогичной проблемой.

Ответ 3

Я использую это решение и, похоже, работает как нужно.

$select->from('product');
$select->where('status = ?', $status);
$select->where('(attribute = ?', $a1);
$select->orWhere('attribute = ?)', $a2);

Ответ 4

Если ваш атрибут является одним и тем же столбцом таблицы, и вы хотите проверить его на одно из нескольких значений, вы можете использовать IN:

$select->from('product');
$select->where('status = ?', $status);
$select->where('attribute IN (?)', [$a1, $a2, ...]);

или

$select->where('attribute IN (:someName)');
$select->setParameter('someName', [$a1, $a2, ...]);

В противном случае я не вижу альтернативы вышеизложенному решению с "attribute = $a1 OR attribute = $a2"