2016-06-13 13 views
5

ich den Fehler 'Cardinality Verletzung' ich immer, für das folgende SQL:DBAL Kardinalität Verletzungsfehler

Lehre \ DBAL \ Exception \ DriverException: Eine Ausnahme ist aufgetreten, während Ausführung

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 

mit params ["% big%", "% light%"]: SQLSTATE [21000]: Kardinalitätsverletzung: 1241 Der Operand sollte 1 Spalte (n) enthalten.

Der Fehler tritt nur auf, wenn mehr als ein Wert in der Parameterliste für WHERE (p.name LIKE (?, ?)) definiert ist.

Ich verwende executeQuery(), und übergibt das Array als Connection::PARAM_STR_ARRAY. In der ursprünglichen Aussage bin definieren ich den Störungspunkt als:

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

Es wird ein Array bekommen als partial_names bestanden nicht mag scheint. Irgendwelche Ideen darüber, was das verursacht und wie man es vermeidet?

+0

Siehe auch http: // Stacko verflow.com/questions/1127088/mysql-like-in – bishop

+0

Was hat Sie dazu gebracht, dass mysql LIKE mehr als ein Argument akzeptiert? –

+0

@YourCommonSense Da 'foo LIKE ('bar')' in MySQL gültig ist, denke ich, dass es natürlich ist zu glauben, dass 'foo LIKE ('bar', 'baz') 'auch gültig wäre. – bishop

Antwort

8

MySQL LIKE ist eine "Zeichenkettenvergleichsfunktion" und vergleicht als solche eine Zeichenkette mit einer anderen, die "einfache Mustererkennung" verwendet.

Wenn Sie die SQL standard überprüfen, werden Sie feststellen, dass die BNF grammar for LIKE akzeptiert nur "zeichenartige" und "Oktett-artige" Argumente, die beide im Wesentlichen, was wir Strings nennen würden. (Es gibt einige Details rund um die Tatsache, dass LIKE führt eine binäre, Zeichen für Zeichen Spiel auf der RHS, das als unterschiedlich ist, wie = arbeitet. foo LIKE 'bar' und foo='bar' zu unterschiedlichen Ergebnissen führen kann)

All dies bedeutet, dass Sie kann nicht do LIKE ('a', 'b'), weil der columnare Ausdruck ('a', 'b') nicht String-like ist. Oder in geeky Standardsprache, es ist Kardinalität (2) unterscheidet sich von der erwarteten Kardinalität (1). Allerdings können Sie dies in MySQL und SQLite (vielleicht auch andere Motoren):

WHERE foo LIKE ('%bar') 

weil die Mächtigkeit der RHS 1 ist (es gibt eine Spalte), das, was LIKE erwartet.

Sie wollen etwas effektiv ähnlich wie foo LIKE IN ('a', 'b'), aber das existiert auch nicht (für den SQL-Standard Grund oben erwähnt). This Q&A zeigt einige Problemumgehungen für dieses Verhalten, REGEXP basierend auf der akzeptierten Antwort.

Also, um diesen Fehler zu umgehen, müssen Sie Ihre Abfrage neu schreiben, um mehrere LIKE oder REGEXP oder vielleicht sogar etwas wie FIND_IN_SET zu verwenden.

2

ändern

(p.name LIKE (?, ?)) 

zu

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

und

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

zu

"%big%", "%light%"