Obsahuje tabulka daný text?
Školení, která pořádám
Jaký dotaz je nejlepší položit, pokud nás zajímá, zda jakýkoliv záznam v tabulce obsahuje určitou hodnotu, a už nás nezajímá, který záznam to je ani kolik jich je? Takový dotaz můžeme použít např. tehdy, když uživatel hledá v novinkách a my mu chceme nabídnout i vyhledávání v jiných objektech. Začněme prvním, co nás napadne:
<?php
mysql_num_rows(mysql_query("SELECT * FROM tabulka WHERE obsah LIKE '%" . mysql_real_escape_string($_GET["search"]) . "%'"));
// poprvé: 1.0481 s, potřetí: 0.4241 s
?>
Tento dotaz je nešikovný v tom, že prohledává všechny řádky a vrací nám obsah všech sloupců, který vůbec nepotřebujeme. Výše uvedený kód se obvykle nahrazuje tímto:
<?php
mysql_result(mysql_query("SELECT COUNT(*) FROM tabulka WHERE obsah LIKE '%" . mysql_real_escape_string($_GET["search"]) . "%'"), 0);
// poprvé: 0.7361 s, potřetí: 0.0505 s
?>
Dotaz vrací jedinou hodnotu, pořád ale prochází všechny řádky. Nás celkový počet záznamů nezajímá, chceme vědět jen ano/ne. Vrátíme se proto pokorně k prvnímu kódu, ale počet výsledků omezíme klauzulí LIMIT a místo všech sloupců si buď můžeme vybrat nějaký krátký (obvykle id
) nebo jít ještě o krok dále a nechat si vrátit pouze konstantu:
<?php
mysql_num_rows(mysql_query("SELECT 1 FROM tabulka WHERE obsah LIKE '%" . mysql_real_escape_string($_GET["search"]) . "%' LIMIT 1"));
// poprvé: 0.2756 s, potřetí: 0.0499 s
?>
Diskuse
Dan Péder:
MySQL nemá operátor exists?
Onecar:
To je opravdu dobré, jsem rád, že znám nejrychlejší metodu :-).
maros:
a co ak chcem zistit to iste, ale je aj jedno, v ktorom stlpci? napr. vyhladavanie v tabulke clankov s nadpisom, uvodom a telom clanku...
Jakub Vrána :
Potom je nutné všechny sloupce v podmínce vyjmenovat a oddělit pomocí OR. Někoho by mohlo napadnout ještě něco jako CONCAT(sloupec1, sloupec2) LIKE ..., ale tam je problém s jednoznačným oddělovačem.
Jakub:
Je lepší použít?
Toto
mysql_num_rows(mysql_query("SELECT 1 FROM tabulka WHERE obsah LIKE '%$_GET[search]%' LIMIT 1"));
nebo toto?
mysql_num_rows(mysql_query("SELECT 1 FROM tabulka WHERE obsah LIKE '%".$_GET["search"]."%' LIMIT 1"));
díky
Vlasta Neubauer:
v sql dotazu ani jedno. je lepší hodnotu $_GET["search"] před použitím nějak 'ošetřit'. ale jinak je to celkem fuk. já preferuji kratší variantu.
Pavel:
Davat $_GET[search] i do takoveto ukazky, ktera vubec pro svoji funkci nepotrebuje predstirat predani pomoci metody GET, to je proste uchylnost.
Jakub Vrána :
Nejčastěji vyhledáváme přece to, co dostaneme od uživatele.
D1ce:
IMHO je lepší všude cpát jednoduché uvozovky, a spojovat:
mysql_num_rows(mysql_query('SELECT 1 FROM tabulka WHERE obsah LIKE \'%'.$_GET['search'].'%\' LIMIT 1'));
Protože řetězec v jednoduchých uvozovkách se(jak bych to řek) neanalizuje nebo neparsuje tak jako řetězec ve dvoitých na vložené proměnné, escapované sekvence apod.
dgx:
Proč by to mělo být lepší? Naopak, vkládání proměnných "...$x..." je pěkná feauture. A rozhodně přispívá k čitelnosti zdrojáku. Řekl bych, že i docela značně.
uzivatel:
No na mnohych frameworkoch sa zauzivalo pouzivanie pri uvodzovkach pouzivat {$premenna}
Pri znakoch, ktore nie su dobre vidiet to celkom pomoze. Ale ak sa v kode vyskytuje mnoho premennych blizko seba je z toho pekny bordel.
trta:
malicko mimo tema, ale nekdy se muze hodit dotaz typu
SELECT SQL_CALC_FOUND_ROWS ... LIMIT ..
a nasledne
SELECT FOUND_ROWS()
kde ten druhy dotaz vrati pocet radku vracenych v dotazu, kdyz by nebyla aplikovana klauzule LIMIT...
Jan:
Dobrý den, mám dotaz pokud použiji toto:
mysql_num_rows(mysql_query("SELECT 1 FROM tabulka WHERE obsah LIKE '%" . mysql_real_escape_string($_GET["search"]) . "%' LIMIT 1"));
u textu, který obsahuje diakritiku my to vráti, že v dtb a není a přitom tam je. Prosím o radu co stím. Děkuji
Jan:
Vyřešeno omlouvám se za spam.
Diskuse je zrušena z důvodu spamu.