Pouze tento týden sleva až 80% na e-learning týkající se Kotlinu. Zároveň využij akci až 30 % zdarma při nákupu e-learningu - Více informací.
Hledáme nové posily do ITnetwork týmu. Podívej se na volné pozice a přidej se do nejagilnější firmy na trhu - Více informací.
discount week 30

Lekce 6 - MySQL krok za krokem: Výběr dat (vyhledávání)

V předešlém cvičení, Řešené úlohy k 1.-5. lekci MySQL/MariaDB, jsme si procvičili nabyté zkušenosti z předchozích lekcí.

Dnes se zaměříme na tu nejhezčí část a tou je výběr dat. Jedná se o dotazování na data, jestli chcete, tak vyhledávání v tabulce.

Výběr dat je klíčovou funkcí databází, umožňuje nám totiž pomocí relativně jednoduchých dotazů dělat i složité výběry dat. Od prostého výběru uživatele podle jeho id (např. pro zobrazení detailů v aplikaci) můžeme vyhledávat uživatele splňující určité vlastnosti, výsledky řadit dle různých kritérií nebo dokonce do dotazu zapojit více tabulek, různé funkce a skládat dotazy do sebe (o tom až v dalších dílech).

Testovací data

Před zkoušením dotazů je vždy dobré mít nějaká testovací data, abychom měli s čím pracovat a neměli tam jen 4 uživatele. Pojďme si do naší tabulky uzivatele vložit nějaké záznamy, aby bylo s čím pracovat. Něco jsem vám připravil. Tabulku si nejprve vyprázdněte (abychom měli stejná data):

DELETE FROM `uzivatele`;

Dále spusťte následující SQL dotaz:

INSERT INTO `uzivatele` (
        `jmeno`,
        `prijmeni`,
        `datum_narozeni`,
        `pocet_clanku`
)
VALUES
('Jan',  'Novák',  '1984-11-03', 17),
('Tomáš', 'Marný', '1942-10-17', 12),
('Josef', 'Nový', '1958-7-10', 5),
('Alfons', 'Svoboda', '1935-5-15', 6),
('Ludmila', 'Dvořáková', '1967-4-17', 2),
('Petr', 'Černý', '1995-2-20', 1),
('Vladimír', 'Pokorný', '1984-4-18', 1),
('Ondřej', 'Bohatý', '1973-5-14', 3),
('Vítezslav', 'Churý', '1969-6-2', 7),
('Pavel', 'Procházka', '1962-7-3', 8),
('Matěj', 'Horák', '1974-9-10', 0),
('Jana', 'Veselá', '1976-10-2', 1),
('Miroslav', 'Kučera', '1948-11-3', 1),
('František', 'Veselý', '1947-5-9', 1),
('Michal', 'Krejčí', '1956-3-7', 0),
('Lenka', 'Němcová', '1954-2-11', 5),
('Věra', 'Marková', '1978-1-21', 3),
('Eva', 'Kučerová', '1949-7-26', 12),
('Lucie', 'Novotná', '1973-7-28', 4),
('Jaroslav', 'Novotný', '1980-8-11', 8),
('Petr', 'Dvořák', '1982-9-30', 18),
('Jiří', 'Veselý', '1961-1-15', 2),
('Martina', 'Krejčí', '1950-8-29', 4),
('Marie', 'Černá', '1974-2-26', 5),
('Věra', 'Svobodová', '1983-3-2', 2),
('Pavel', 'Dušín', '1991-5-1', 9),
('Otakar', 'Kovář', '1992-12-17', 9),
('Kateřina', 'Koubová', '1956-11-15', 4),
('Václav', 'Blažek', '1953-10-20', 6),
('Jan', 'Spáčil', '1967-5-6', 3),
('Zdeněk', 'Malačka', '1946-3-10', 6);

V databázi máme 31 uživatelů. To by mělo stačit k tomu, abyste si na nich vyzkoušeli základy dotazování.

(Mimochodem, všimněte si, že se dá VALUES v příkazu INSERT vložit najednou více, vloží se tak více položek v jednom dotazu).

Dotazování

Dotaz na data, tedy jejich vyhledání/výběr naleznete v prostředí phpMyAdmin pod položkou Vyhledat v horní liště. Můžete si to zkusit, stačí zadat nějakou hodnotu do sloupce hodnota. Pokud jich zadáte více, bude se hledat podle více hodnot. Operátory zatím neřešte, vysvětlíme si je dále.

Vyledávání v phpMyAdmin

phpMyAdmin byl pro nás zpočátku takovou berličkou, ale nyní pro nás již přestává být zajímavý. Budeme ho používat hlavně pro spouštění dotazů a ukazování jejich výsledků.

Po vyhledání nám phpMyAdmin ukáže dotaz SELECT. Vždy tam píše něco navíc, než je doopravdy potřeba. Základní dotaz pro výběr všech Janů z tabulky by vypadal takto:

SELECT * FROM `uzivatele` WHERE `jmeno` = 'Jan';

Příkaz je asi srozumitelný, ta hvězdička označuje, že chceme vybrat všechny sloupce. Dotaz tedy česky zní: "Vyber všechny sloupce z tabulky uzivatele, kde je jméno Jan".

Výsledek dotazu nám phpMyAdmin zobrazí, měli byste vidět toto:

8    Jan    Novák     1984-11-03    17
37   Jan    Spáčil    1967-05-06    3

Tabulky mají většinou hodně sloupců a většinou nás zajímají jen nějaké. Abychom databázi nezatěžovali přenášením zbytečných dat zpět do naší aplikace, budeme se snažit vždy specifikovat ty sloupce, které chceme. Dejme tomu, že budeme chtít jen příjmení lidí, co se jmenují Jan a ještě počet jejich článků. Dotaz upravíme:

SELECT `prijmeni`, `pocet_clanku` FROM `uzivatele` WHERE `jmeno` = 'Jan';
Tento výukový obsah pomáhají rozvíjet následující firmy, které dost možná hledají právě tebe!

Výsledek:

Novák     17
Spáčil    3

Opravdu nebuďte líní a pokud nepotřebujete téměř všechny sloupce, vyjmenujte v SELECTu ty, jejiž hodnoty vás v tu chvíli zajímají. Vždy se snažte podmínku omezit co nejvíce již na úrovni databáze, ne že si vytaháte celou tabulku do aplikace a tam si ji vyfiltrujete. Řekněme, že by vaše aplikace poté nebyla úplně rychlá :) Výčet sloupců, které má dotaz vrátit, nemá nic společného s dalšími sloupci, které v dotazu používáme. Můžeme tedy vyhledávat podle deseti sloupců, ale vrátit jen jeden.

Stejně jako tomu bylo u DELETE, i zde bude fungovat pouze dotaz:

SELECT * FROM `uzivatele`;

Tehdy budou vybráni úplně všichni uživatelé z tabulky.

U podmínkování platí to samé, jako u DELETE, klauzule WHERE funguje úplně stejně. Zkusme si to. Vyberme všechny uživatele, narozené po roce 1960 a s počtem článků vyšším než 5:

SELECT * FROM `uzivatele` WHERE `datum_narozeni` >= '1960-1-1' AND `pocet_clanku` > 5;

Výsledek:

8     Jan          Novák        1984-11-03    17
16    Vítezslav    Churý        1969-06-02    7
17    Pavel        Procházka    1962-07-03    8
27    Jaroslav     Novotný      1980-08-11    8
28    Petr         Dvořák       1982-09-30    18
33    Pavel        Dušín        1991-05-01    9
34    Otakar       Kovář        1992-12-17    9

Operátory

Základní operátory =, >, <, >=, <=, != určitě umíte použít. V SQL máme ale další, řekněme si o LIKE, IN a BETWEEN.

LIKE

LIKE umožňuje vyhledávat textové hodnoty jen podle části textu. Funguje podobně, jako operátor "=" (rovná se), pouze můžeme používat 2 zástupné znaky:

  • % (procento) označuje libovolný počet libovolných znaků.
  • _ (podtržítko) označuje jeden libovolný znak.

Pojďme si vyzkoušet několik dotazů s operátorem like. Najděme příjmení lidí začínající na "S":

SELECT `prijmeni` FROM `uzivatele` WHERE `prijmeni` LIKE 's%';

Zadáme normálně text v apostrofech, pouze na některá místa můžeme vložit speciální znaky. Na velikosti písmen nezáleží (hledání je tedy case-insensitive). Výsledek dotazu bude následující:

Svoboda
Svobodová
Spáčil

Nyní zkusme najít pětipísmenná příjmení, která mají jako 2. znak "O":

SELECT `prijmeni` FROM `uzivatele` WHERE `prijmeni` LIKE '_o___';

Výsledek:

Novák
Horák
Kovář

Asi již tušíte, jak LIKE funguje. Použití lze vymyslet hodně, většinou se používá s procenty na obou stranách pro fulltextové vyhledávání (např. slova v textu článku).

IN

IN umožňuje vyhledávat pomocí výčtu prvků. Udělejme si tedy výčet jmen a vyhledejme uživatelé s těmito jmény:

SELECT `jmeno`, `prijmeni` FROM `uzivatele` WHERE `jmeno` IN ('Petr', 'Jan', 'Kateřina');

Výsledek:

Jan         Novák
Petr        Černý
Petr        Dvořák
Kateřina    Koubová
Jan         Spáčil

Operátor IN se používá ještě u tzv. poddotazů, ale na ty máme ještě dost času :)

BETWEEN

Poslední operátor, který si dnes vysvětlíme, je BETWEEN (tedy mezi). Není ničím jiným, než zkráceným zápisem podmínky ">= AND <=". Již víme, že i datumy můžeme normálně porovnávat, najděme si uživatele, kteří se narodili mezi lety 1980 a 1990:

SELECT `jmeno`, `prijmeni`, `datum_narozeni` FROM `uzivatele` WHERE `datum_narozeni` BETWEEN '1980-1-1' AND '1990-1-1';

Mezi 2 hodnoty píšeme operátor AND.

Výsledek:

Jan         Novák        1984-11-03
Vladimír    Pokorný      1984-04-18
Jaroslav    Novotný      1980-08-11
Petr        Dvořák       1982-09-30
Věra        Svobodová    1983-03-02

Vzorový příklad BETWEEN a jeho alternativní zápis >= AND <= přináší očekávané výsledky vztahující se především k typu date, u typu datetime, který bývá častěji používán, dochází k mírně odlišným výsledkům:

SELECT * FROM x WHERE a BETWEEN '2021-03-30' AND '2021-03-31';

x = tabulka; a = sloupec porovnávaný pro podmínku. Dotaz je pouze instruktážní.

Výsledek u typu date zahrne dva datumy:

2021-03-30
2021-03-31

Výsledek u typu datetime zahrne pouze jedno datum:

2021-03-30

Při použití typu datetime, který se zapisuje ve tvaru např. 2021-03-31 23:59:59, můžeme použít funkci DATE_ADD(), ta přidá 1 den. Tím docílíme sjednocení výsledků a zachováme datumové vymezení:

SELECT * FROM x WHERE a BETWEEN '2021-03-30' AND DATE_ADD('2021-03-31',INTERVAL 1 DAY);

Docílíme očekávaného výsledku:

2021-03-30
2021-03-31

To je pro dnešek vše. U výběru dat zůstaneme ještě několik dílů, vlastně většinu tohoto seriálu.

V následujícím cvičení, Řešené úlohy k 6. lekci MySQL/MariaDB, si procvičíme nabyté zkušenosti z předchozích lekcí.


 

Předchozí článek
Řešené úlohy k 1.-5. lekci MySQL/MariaDB
Všechny články v sekci
MySQL/MariaDB databáze krok za krokem
Přeskočit článek
(nedoporučujeme)
Řešené úlohy k 6. lekci MySQL/MariaDB
Článek pro vás napsal David Čápka
Avatar
Uživatelské hodnocení:
95 hlasů
David je zakladatelem ITnetwork a programování se profesionálně věnuje 13 let. Má rád Nirvanu, sushi a svobodu podnikání.
Unicorn university David se informační technologie naučil na Unicorn University - prestižní soukromé vysoké škole IT a ekonomie.
Aktivity

 

 

Komentáře
Zobrazit starší komentáře (24)

Avatar
Jan Sagi
Člen
Avatar
Jan Sagi:17.11.2019 8:17

Ahoj prosím o radu už několik večeru jsem se nepohnul z místa...
proč my nefunguje výběr dat

$uzivatele = Db::queryall('
SELECT * FROM `hrydata` WHERE `nazev` LIKE '%fifa%'
 ');
print_r($uzivatele);

Warning: Use of undefined constant fifa - assumed 'fifa' (this will throw an Error in a future version of PHP) in /hosting/www/hry­data.cz/www/ta­bulkaproduktu­.php on line 13

Warning: A non-numeric value encountered in /hosting/www/hry­data.cz/www/ta­bulkaproduktu­.php on line 13

Warning: A non-numeric value encountered in /hosting/www/hry­data.cz/www/ta­bulkaproduktu­.php on line 13

Fatal error: Uncaught DivisionByZero­Error: Modulo by zero in /hosting/www/hry­data.cz/www/ta­bulkaproduktu­.php:13 Stack trace: #0 {main} thrown in /hosting/www/hry­data.cz/www/ta­bulkaproduktu­.php on line 13

moc děkuji za radu

 
Odpovědět
17.11.2019 8:17
Avatar
Odpovídá na Jan Sagi
Michal Šmahel:17.11.2019 17:35

Ahoj, máš problém v označení hraničních bodů řetězců. Pro řetězec s SQL dotazem používáš apostrofy ('), ale hodnotu uvnitř SQL řetězce máš označenou taktéž apostrofy ('). Toto způsobí chaos v PHP, protože v tu chvíli tam máš 2 řetězce a mezi nimi %fifa%.

Řešení je prosté - na jednom místě prohodit apostrofy (') za uvozovky ("). Mohlo by to poté vypadat třeba takto:

$uzivatele = Db::queryall("
    SELECT * FROM `hrydata` WHERE `nazev` LIKE '%fifa%'
");
print_r($uzivatele);
Editováno 17.11.2019 17:36
Odpovědět
17.11.2019 17:35
Nejdůležitější je motivace, ovšem musí být doprovázena činy.
Avatar
Jan Sagi
Člen
Avatar
Odpovídá na Michal Šmahel
Jan Sagi:17.11.2019 20:00

Moc děkuji za radu funguje to super

 
Odpovědět
17.11.2019 20:00
Avatar
Pavel Kubalík:30.9.2020 14:06

Dobrý den
Jsem opět nadšen ze všeho (ITnetwork, kurzy, MySQL).
Konečně jsem pochopil, že zpětná lomítka nemusím pracně naklikávat, ale že stačí vybrat položku ze seznamu. Vzhledem k tomu, že syntaxi jsem již probíral v kurzu SQLite, byl jsem s lekcí brzo hotov.
Opět jsem spokojen.
Děkuji PK

 
Odpovědět
30.9.2020 14:06
Avatar
Zdeněk Beránek:25.5.2021 13:02

Ahoj, mám dotaz na zmíněný operátor nerovno !=. Na W3 school (https://www.w3schools.com/…perators.asp) jsem ho nenašel, ale místo něj tento <>.

 
Odpovědět
25.5.2021 13:02
Tento výukový obsah pomáhají rozvíjet následující firmy, které dost možná hledají právě tebe!
Avatar
Samuel Hél
Tým ITnetwork
Avatar
Odpovídá na Zdeněk Beránek
Samuel Hél:26.5.2021 9:54

Ahoj, operátory mají stejnou funkci. Operátor != se možná bude lépe pamatovat, protože to můžeš přečíst jako NOT EQUAL, mezitím <> ti úplně nenapoví. Navíc v C# operátor <> neexistuje, takže pro Csharpery by to bylo více matoucí a hůř zapamatovatelné :)

 
Odpovědět
26.5.2021 9:54
Avatar
Jiří Procházka:21. března 21:24

Ty roky se dají dělat také přirozeně takto: SELECT jmeno, prijmeni, datum_narozeni FROM uzivatele WHERE YEAR(datum_narozeni) BETWEEN '1980' AND '1990'

 
Odpovědět
21. března 21:24
Avatar
Jiří Procházka:21. března 21:47

Smazat please...

Editováno 21. března 21:49
 
Odpovědět
21. března 21:47
Avatar
Jaroslav Drobek:12. dubna 17:00

Hodnocení:

  • "..všimněte si.." - všímaví si všimli už ve 3 lekci..
  • "Vždy tam píše něco navíc, než je doopravdy potřeba." - to jsem potřeboval vědět už ve 2. lekci. Na tomto místě ovšem phpMyAdmin zarputile vypisuje jen to nutné, ba vynechává středník - asi nějaká lepší verze 😉
  • "Stejně jako tomu bylo u DELETE" - u DELETE nemusela být hvězdička.
 
Odpovědět
12. dubna 17:00
Avatar
Jaroslav Drobek:12. dubna 17:01

Hodnocení (pokračování):

  • Vysvětlení rozdílu mezi date a dateline není moc přesvědčivé, "instruktážní" příklad neobsahuje informaci o zdroji dat, takže vůbec nelze funkčnost jednoznačně odvodit. Možná ale čtenáře napadne, že jde o pokus vysvětlit vyhledávání v uzavřeném (date) a polouzavřeném (datetime - zdola uzavřeném, shora otevřeném) intervalu. Funkce DATE_ADD pak jistě nepřidává 1 den, ale pouze onu horní mez uvažovaného intervalu..
Editováno 12. dubna 17:02
 
Odpovědět
12. dubna 17:01
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 10 zpráv z 34. Zobrazit vše