Na základě příkladu FIND_IN_SET() od @Jeremy Smith to můžete udělat pomocí spojení, takže nemusíte spouštět poddotaz.
SELECT * FROM table t
JOIN locations l ON FIND_IN_SET(t.e_ID, l.city) > 0
WHERE l.e_ID = ?
Je známo, že tato funkce funguje velmi špatně, protože musí provádět skenování tabulek a vyhodnocovat funkci FIND_IN_SET() pro každé kombinace řádků v table
a locations
. Nemůže používat index a neexistuje způsob, jak jej zlepšit.
Vím, že jste řekl, že se snažíte co nejlépe využít špatný návrh databáze, ale musíte pochopit, jak drasticky špatné to je.
Vysvětlení:Předpokládejme, že bych vás chtěl požádat, abyste vyhledali každého v telefonním seznamu, jehož první, střední nebo poslední iniciála je "J." Seřazené pořadí knihy v tomto případě nijak nepomůže, protože stejně musíte skenovat každou jednotlivou stránku.
LIKE
řešení poskytnuté @fthiella má podobný problém, pokud jde o výkon. Nelze jej indexovat.
Podívejte se také na mou odpověď na Je ukládání seznamu s oddělovači ve sloupci databáze opravdu tak špatné? pro další úskalí tohoto způsobu ukládání denormalizovaných dat.
Pokud můžete vytvořit doplňkovou tabulku pro uložení rejstříku, můžete namapovat umístění ke každému záznamu v seznamu měst:
CREATE TABLE location2city (
location INT,
city INT,
PRIMARY KEY (location, city)
);
Za předpokladu, že máte vyhledávací tabulku pro všechna možná města (nejen ta uvedená v table
) můžete snést neefektivnost při vytváření mapování:
INSERT INTO location2city (location, city)
SELECT l.e_ID, c.e_ID FROM cities c JOIN locations l
ON FIND_IN_SET(c.e_ID, l.city) > 0;
Nyní můžete spustit mnohem efektivnější dotaz k nalezení položek ve vaší table
:
SELECT * FROM location2city l
JOIN table t ON t.e_ID = l.city
WHERE l.e_ID = ?;
To může využít index. Nyní se musíte postarat o to, aby jakékoli INSERT/UPDATE/DELETE řádků v locations
také vloží odpovídající řádky mapování do location2city
.