Сложное предложение 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"