Ошибка нарушения мощности DBAL


Я получаю ошибку "Нарушение мощности" для следующего SQL:

Доктрина\DBAL\Исключение\Исключение драйвера: Исключение возникло во время выполнения

SELECT p.* FROM mod_products_products p 
LEFT JOIN mod_products_products_categories c_link ON c_link.product_id = p.id 
LEFT JOIN mod_products_brands b ON p.brand_id = b.id 
LEFT JOIN mod_products_groups vg ON p.variation_id = vg.id 
LEFT JOIN mod_products_categories c ON c_link.category_id = c.id 
LEFT JOIN mod_products_group_options vg_o ON vg_o.group_id = vg.id 
LEFT JOIN mod_products_group_values vg_o_v ON vg_o_v.option_id = vg_o.id 
WHERE (p.name LIKE (?, ?)) AND (p.parent_id = 0) AND (vg_o.disabled=0) 
GROUP BY p.id ORDER BY p.name ASC 
LIMIT 18446744073709551615 OFFSET 0

с параметрами ["%большой%", "%легкий%"]: SQLSTATE[21000]: Нарушение мощности: 1241 Операнд должен содержать 1 столбец(ы).

Ошибка возникает только в том случае, если в списке параметров определено более одного значения для WHERE (p.name LIKE (?, ?)).

Я использую executeQuery() и передаю массив как Connection::PARAM_STR_ARRAY. В исходном заявлении я определяю проблемную точку следующим образом:

$builder->andWhere('p.name LIKE (:partial_names)');

Похоже, ему не нравится, когда массив передается как частичные имена. Есть идеи о том, что является причиной этого и как этого избежать?

Author: Your Common Sense, 2016-06-13

2 answers

MySQL, ПОДОБНЫЙ , является "функцией сравнения строк" и, как таковой, сравнивает одну строку с другой, используя "простое сопоставление шаблонов".

Если вы проверите стандарт SQL, вы заметите, что грамматика BNF для LIKE принимает только "символьные" и "октетные" аргументы, оба из которых по сути являются тем, что мы бы назвали строками. (Есть некоторые детали, касающиеся того факта, что LIKE выполняет двоичное сопоставление символов в RHS, которое отличается от того, как работает =: foo LIKE 'bar' и foo='bar' могут давать разные результаты.)

Все это означает, что вы не можете сделать LIKE ('a', 'b'), потому что столбчатое выражение ('a', 'b') не похоже на строку. Или, выражаясь вызывающим стандартным языком, его мощность (2) отличается от ожидаемой мощности (1). Однако вы можете сделать это в MySQL и SQLite (возможно, в других движках):

WHERE foo LIKE ('%bar')

Потому что мощность RHS равна 1 (есть один столбец), что и ожидает LIKE.

Ты требуется что-то эффективно похожее на foo LIKE IN ('a', 'b'), но этого тоже не существует (по причине стандарта SQL, упомянутой выше). Этот вопрос и ответ показывает некоторые обходные пути для такого поведения, REGEXP основанные на принятом ответе.

Итак, чтобы обойти эту ошибку, вам нужно переписать свой запрос, чтобы использовать несколько LIKE, или REGEXP, или, может быть, даже что-то вроде FIND_IN_SET.

 8
Author: bishop, 2017-05-23 12:09:45

Изменение

(p.name LIKE (?, ?))

До

(p.name LIKE ? OR p.name LIKE ?)

И

["%big%", "%light%"]

До

"%big%", "%light%"
 2
Author: Rick James, 2016-06-24 15:56:59