1. Úvod
Výzva při vyhledávání čárkou oddělených dat v MySQL
Při práci s databázemi můžete narazit na situace, kdy jsou v jednom sloupci uloženy více hodnot oddělené čárkami. Například sloupec může obsahovat řetězec jako "1,3,5" a vy chcete získat jen záznamy, které obsahují hodnotu „3“.
V takových případech standardní operátor = nebo klauzule IN často nedávají očekávané výsledky. Důvodem je, že čárkou oddělený řetězec je považován za jeden řetězcový hodnotu, takže porovnání probíhá vůči celému řetězci, nikoli vůči jednotlivým prvkům.
Co je funkce FIND_IN_SET?
V takových situacích se MySQL funkce FIND_IN_SET ukazuje jako velmi užitečná.
Tato funkce vám umožní snadno zjistit, zda zadaná hodnota existuje v čárkou odděleném řetězci.
Například uvažujme následující SQL dotaz:
SELECT * FROM users WHERE FIND_IN_SET('3', favorite_ids);
V tomto dotazu můžete získat záznamy, kde čárkou oddělený řetězec ve sloupci favorite_ids (např. "1,2,3,4") obsahuje hodnotu „3“.
Účel tohoto článku a cílové publikum
Tento článek vysvětluje, jak používat funkci FIND_IN_SET od základů, a to jasně a strukturovaně. Od základní syntaxe po praktické příklady, srovnání s jinými metodami vyhledávání, důležité úvahy a FAQ, tento průvodce poskytuje praktické znalosti pro vývoj v reálném světě.
Článek je určen pro:
- Webové inženýry a backend vývojáře, kteří pravidelně používají MySQL
- Vývojáře, kteří musí pracovat se stávajícími systémy ukládajícími čárkou oddělená data
- Začátečníky v SQL, kteří bojují s částečným porovnáváním a vyhledáváním na základě hodnot
2. Základní syntaxe a chování funkce FIND_IN_SET
Syntaxe FIND_IN_SET
FIND_IN_SET je MySQL funkce sloužící k určení, zda konkrétní hodnota existuje v čárkou odděleném řetězci. Základní syntaxe je následující:
FIND_IN_SET(search_value, comma_separated_string)
Například:
SELECT FIND_IN_SET('3', '1,2,3,4'); -- Result: 3
V tomto příkladu, protože „3“ se nachází na třetí pozici, funkce vrátí číselnou hodnotu 3.
Pravidla návratové hodnoty
Funkce FIND_IN_SET se chová podle následujících pravidel:
| Condition | Result |
|---|---|
| The search value exists in the list | Its position in the list (starting from 1) |
| The search value does not exist | 0 |
| Either argument is NULL | NULL |
Příklad (Vrácení pozice)
SELECT FIND_IN_SET('b', 'a,b,c'); -- Result: 2
Příklad (Hodnota nenalezena)
SELECT FIND_IN_SET('d', 'a,b,c'); -- Result: 0
Příklad (Zahrnuté NULL)
SELECT FIND_IN_SET(NULL, 'a,b,c'); -- Result: NULL
Příklad použití ve WHERE klauzuli
Tato funkce se nejčastěji používá pro filtrování ve WHERE klauzuli.
SELECT * FROM users WHERE FIND_IN_SET('admin', roles);
V tomto příkladu budou vráceny jen řádky, kde sloupec roles obsahuje řetězec „admin“. Pokud sloupec obsahuje hodnotu jako "user,editor,admin", bude to odpovídat.
Důležité poznámky o číslech a řetězcích
FIND_IN_SET provádí porovnání jako řetězce, což znamená, že se chová následovně:
SELECT FIND_IN_SET(3, '1,2,3,4'); -- Result: 3
SELECT FIND_IN_SET('3', '1,2,3,4'); -- Result: 3
Ačkoliv funguje jak s číselnými, tak s řetězcovými hodnotami, nejasné datové typy mohou vést k neočekávanému chování. Proto je nejlepší praxí zacházet s hodnotami explicitně jako řetězce, kdykoli je to možné.
3. Praktické příklady
Vyhledávání ve sloupci, který ukládá čárkou oddělené řetězce
V reálných systémech můžete narazit na situace, kdy jsou v jednom sloupci uloženy více hodnot (např. ID nebo oprávnění) jako čárkou oddělený řetězec. Například uvažujme následující tabulku users.
| id | name | favorite_ids |
|---|---|---|
| 1 | Taro | 1,3,5 |
| 2 | Hanako | 2,4,6 |
| 3 | Jiro | 3,4,5 |
Když chcete „získat uživatele, kteří zahrnují 3“, je funkce FIND_IN_SET mimořádně pohodlná.
SELECT * FROM users WHERE FIND_IN_SET('3', favorite_ids);
Spuštěním tohoto SQL získáte záznamy pro „Taro“ a „Jiro“.
Funguje dobře i když hodnoty vypadají číselně
I když favorite_ids vypadá, že obsahuje čísla, FIND_IN_SET provádí porovnání jako řetězce, takže je nejbezpečnější předat argument jako řetězec v uvozovkách.
-- OK
SELECT * FROM users WHERE FIND_IN_SET('5', favorite_ids);
-- Works, but strictly speaking not recommended
SELECT * FROM users WHERE FIND_IN_SET(5, favorite_ids);
Aby byly dotazy čitelné a chování předvídatelné, doporučuje se explicitně specifikovat hodnotu jako řetězec.
Dynamické vyhledávání (zástupné symboly a proměnné)
Při dynamickém generování SQL z webové aplikace je běžné používat proměnné nebo vázané parametry.
Pokud použijete MySQL proměnnou, vypadá to takto:
SET @target_id = '3';
SELECT * FROM users WHERE FIND_IN_SET(@target_id, favorite_ids);
Při vázání z aplikační vrstvy (např. PHP, Python nebo Node.js) můžete s ním zacházet podobně pomocí zástupných symbolů.
Jak zacházet s vyhledáváním více hodnot
Bohužel, FIND_IN_SET může vyhledávat jen jednu hodnotu najednou.
Pokud chcete získat záznamy, které obsahují „3 nebo 4“, musíte to napsat několikrát pomocí OR.
SELECT * FROM users
WHERE FIND_IN_SET('3', favorite_ids) OR FIND_IN_SET('4', favorite_ids);
Pokud se podmínky stanou složitějšími, měli byste buď dynamicky sestavit SQL ve své aplikaci, nebo zvážit přechod na normalizovanou strukturu tabulky.
4. Porovnání FIND_IN_SET s jinými metodami vyhledávání
Běžné alternativy: IN a LIKE
V MySQL, kromě FIND_IN_SET, můžete také vidět použití klauzule IN nebo klauzule LIKE k ověření, zda je hodnota zahrnuta. Každá metoda se však chová jinak a použití špatné může vést k nesprávným výsledkům dotazu.
Zde si objasníme, jak se liší od FIND_IN_SET a kdy použít který přístup.
Porovnání s klauzulí IN
Klauzule IN se typicky používá k ověření, zda hodnota odpovídá jedné z několika konstantních hodnot.
-- Example of IN (this does NOT search inside "favorite_ids" for the value 3)
SELECT * FROM users WHERE favorite_ids IN ('3');
V tomto případě budou vráceny jen záznamy, kde favorite_ids je přesná shoda pro „3“. To znamená, že hodnoty jako „1,3,5“ nebudou odpovídat – pouze řádek, kde je hodnota sloupce přesně „3“, bude odpovídat.
Naopak, FIND_IN_SET kontroluje pozici prvku v čárkou odděleném seznamu, což vám umožní přesně získat záznamy, které obsahují „3“, například takto:
SELECT * FROM users WHERE FIND_IN_SET('3', favorite_ids);
✅ Klíčové doporučení pro použití:
IN: Používejte s normalizovanými tabulkami (např.SELECT * FROM posts WHERE category_id IN (1, 3, 5))FIND_IN_SET: Používejte s denormalizovanými řetězci oddělenými čárkami
Porovnání s klauzulí LIKE
Technicky můžete použít LIKE pro částečné shody, ale s sebou nese důležité úskalí.
-- A common mistake with LIKE
SELECT * FROM users WHERE favorite_ids LIKE '%3%';
Tento dotaz ve skutečnosti neznamená „obsahuje hodnotu 3“ – odpovídá jakémukoli řetězci, který obsahuje znak „3“, což může nesprávně odpovídat „13“, „23“ nebo „30“.
To znemožňuje spolehlivě zjistit, zda 3 existuje jako samostatná hodnota.
✅ Klíčové doporučení pro použití:
LIKE: Užitečné pro fuzzy (přibližné) textové vyhledávání, ale nedokáže rozpoznat hranice oddělené čárkamiFIND_IN_SET: Přesně kontroluje shodu samostatných hodnot v čárkou oddělených seznamech
Výkonnostní rozdíly
| Method | Uses Index | Search Target | Speed |
|---|---|---|---|
IN | Yes | Number or single value | ◎ Very fast |
LIKE | Depends on pattern | Text scan | △ Can become slow depending on conditions |
FIND_IN_SET | No | Full scan | × May be slow |
Konkrétně FIND_IN_SET nemůže využívat indexy a často spouští úplné skenování tabulky. Pokud pracujete s velkými datovými sadami, možná budete muset přehodnotit schéma.
5. Důležité poznámky a osvědčené postupy
Není kompatibilní s hodnotami obsahujícími čárky
FIND_IN_SET předpokládá jednoduchý seznam hodnot oddělených čárkami. Proto pokud jednotlivý prvek v seznamu sám obsahuje čárku, funkce se nebude chovat podle očekávání.
Nesprávný příklad:
SELECT FIND_IN_SET('1,2', '1,2,3,4'); -- Result: 1
Používání tímto způsobem může vést k nesprávným shodám, protože celý řetězec je vyhodnocován nesprávně.
Tuto funkci byste měli používat pouze tehdy, když můžete zaručit, že jednotlivé hodnoty neobsahují čárky.
Výkonnostní problémy
Protože FIND_IN_SET nemůže využívat indexy, provádí úplné prohledání tabulky. V důsledku toho může při použití na velkých tabulkách výkon dotazu výrazně klesnout.
Řešení:
- Místo ukládání hodnot oddělených čárkami normalizujte vztah a spravujte jej v samostatné tabulce.
- V prostředích, kde je výkon kritický, zvažte rozšíření pomocí dočasných tabulek nebo strategii založenou na JOIN.
For example, if you create an intermediate table such as user_favorites, you can take advantage of indexes for faster searches:
SELECT users.*
FROM users
JOIN user_favorites ON users.id = user_favorites.user_id
WHERE user_favorites.favorite_id = 3;
Čitelnost a údržba
Ačkoliv se FIND_IN_SET může zdát pohodlný, přináší několik nevýhod:
- Dotazy nejsou intuitivní (vrací pozicové hodnoty)
- Přidávání nebo odstraňování hodnot je obtížné
- Dodržování integrity dat je obtížné vynutit (více významů v jednom sloupci)
Proto, když je důležitá udržovatelnost a integrita dat, revize samotného schématu je často nejlepší praxí.
Kdy musíte použít FIND_IN_SET
Existují situace, kdy nemáte jinou možnost než pracovat s sloupci oddělenými čárkami – například v legacy systémech nebo u produktů třetích stran. V takových případech zvažte následující opatření:
- Nejprve použijte další podmínky filtrování, aby se zúžil rozsah vyhledávání
- Zabránit chybám formátování, jako jsou dvojité čárky nebo mezery na začátku/konec
- Provádět doplňující zpracování na úrovni aplikace, pokud je to možné
6. Často kladené otázky (FAQ)
Může FIND_IN_SET používat indexy?
Ne, FIND_IN_SET nemůže používat indexy. Interně řetězec rozdělí a vyhodnotí, takže nevyužívá optimalizaci indexů MySQL.
V důsledku toho může jeho použití na velkých tabulkách zpomalení výkon dotazu. Pro systémy, kde je výkon kritický, zvažte přepracování schématu nebo normalizaci dat.
Funguje správně s kombinací čísel a řetězců?
Obecně ano – ale mějte na paměti, že porovnání se provádí jako řetězce. Pokud jsou smíchány číselné a řetězcové hodnoty, může dojít k neočekávanému chování.
Například oba následující příklady vrátí shodu pro 3:
SELECT FIND_IN_SET(3, '1,2,3,4'); -- Result: 3
SELECT FIND_IN_SET('3', '1,2,3,4'); -- Result: 3
Nicméně v případech jako FIND_IN_SET('03', '01,02,03') může formátování s úvodními nulami ovlivnit chování shody.
Nejbezpečnější je standardizovat formátování hodnot.
Jak mohu najednou vyhledat více hodnot?
Protože FIND_IN_SET přijímá pouze jednu vyhledávací hodnotu, pokud chcete vyhledat záznamy obsahující „3 nebo 4“, musíte jej volat vícekrát pomocí OR:
SELECT * FROM users
WHERE FIND_IN_SET('3', favorite_ids)
OR FIND_IN_SET('4', favorite_ids);
Pokud se podmínky stanou složitějšími, zvažte dynamické vytváření SQL na úrovni aplikace nebo přechod na normalizovanou strukturu tabulky.
FIND_IN_SET způsobuje výkonnostní problémy. Co mám dělat?
Následující strategie jsou účinné:
- Přepněte na normalizovaný návrh tabulky
- Nejprve použijte podmínky filtrování, aby se zúžil rozsah vyhledávání
- Používejte ji pouze při práci s malými datovými sadami
- Zvažte přechod na strukturované formáty, jako je full-textové vyhledávání nebo datové typy JSON
Moderní verze MySQL podporují datové typy JSON. Například pokud spravujete sloupec roles jako JSON pole, můžete použít JSON_CONTAINS() pro flexibilní a efektivní vyhledávání.
Bude FIND_IN_SET v budoucnu označen jako zastaralý?
Od MySQL 8.0 není FIND_IN_SET oficiálně označen jako zastaralý. Nicméně denormalizované datové struktury (sloupce s hodnotami oddělenými čárkami) nejsou doporučeny, takže praktické používání této funkce se v průběhu času pravděpodobně sníží.
Při přepracování databáze je ideální přejít na normalizované struktury nebo návrhy založené na JSON.
7. Závěr
Přehled vlastností a výhod FIND_IN_SET
FIND_IN_SET funkce je mimořádně užitečná v MySQL při vyhledávání řetězců oddělených čárkami. Je zvláště užitečná, když potřebujete získat záznamy, které obsahují konkrétní hodnotu v jediném sloupci ukládajícím více hodnot.
Díky své jednoduché syntaxi umožňuje kontrolu samostatných shod hodnot, které je obtížné přesně dosáhnout pomocí klauzulí LIKE nebo IN. Tato schopnost detekovat jednotlivé prvky v seznamu odděleném čárkami je její největší předností.
Důležité úvahy při jejím používání
Současně existuje několik omezení a důležitých úvah, takže by neměla být používána nadměrně bez pečlivého zvážení:
- Indexy nelze použít (což může zpomalit vyhledávání)
- Není kompatibilní s hodnotami, které obsahují čárky
- Předpokládá denormalizovanou strukturu
- Podporuje pouze vyhledávání jedné hodnoty (více vyhledávání vyžaduje podmínky
OR)
Pochopení těchto charakteristik je nezbytné pro správné používání funkce.
Kdy byste ji měli — a neměli — použít
| Situation | Should You Use It? | Reason |
|---|---|---|
| Small dataset, infrequent searches | ✅ Yes | Easy to implement and low development cost |
| Dependent on a legacy system structure | ✅ Use selectively | Useful when refactoring is difficult |
| Large dataset, high-frequency access | ❌ Not recommended | Performance degradation becomes significant |
| Schema can be normalized | ❌ Avoid | JOINs or intermediate tables are more efficient |
Jak to aplikovat v praxi
- Pochopte ji jako flexibilní nástroj pro práci v rámci existujících databázových struktur
- Použijte ji jako referenční bod při rozhodování, zda v budoucnu přejít na normalizovaný návrh dat
- Místo toho, abyste ji používali jako rychlé řešení, jasně pochopte, co funkce ve skutečnosti dělá
Pro vývojáře, kteří upřednostňují udržovatelnost a čitelnost, je nejlepší považovat tuto funkci za něco, co můžete „používat dočasně – ale nakonec se od ní odklonit.“


