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
?>
Jakub Vrána, Dobře míněné rady, 25.12.2006, diskuse: 16 (nové: 0)

Diskuse

Dan Péder:

MySQL nemá operátor exists?

ikona Jakub Vrána OpenID:

Má.

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...

ikona Jakub Vrána OpenID:

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.

ikona Jakub Vrána OpenID:

Nejčastěji vyhledáváme přece to, co dostaneme od uživatele.

ikona 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.

ikona 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...

ikona Jakub Vrána OpenID:

Někdy se to může hodit, ale ne v tomto případě. Napsal jsem o tom samostatný článek: http://php.vrana.cz/ziskani-poctu-radek.php

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.

avatar © 2005-2024 Jakub Vrána. Publikované texty můžete přetiskovat pouze se svolením autora. Ukázky kódu smíte používat s uvedením autora a URL tohoto webu bez dalších omezení Creative Commons. Můžeme si tykat. Skripty předpokládají nastavení: magic_quotes_gpc=Off, magic_quotes_runtime=Off, error_reporting=E_ALL & ~E_NOTICE a očekávají předchozí zavolání mysql_set_charset. Skripty by měly být funkční v PHP >= 4.3 a PHP >= 5.0.