Warning
This page is located in archive.

SQL dotazy - SELECT

Připojení k databázi

V této hodině budeme pracovat s demonstrační databází Foodmart. Ta obsahuje data z datového skladu popisujícího prodeje jídla a doprovodné informace. Zde budeme pracovat s tabulkou zaměstnanci (table employee) a tabulkou sklady (table store). Vztah mezi těmito tabulkami je 1:N.

K databázi se připojíme pomocí programu Pgadmin3.

Vytvoříme připojení k serveru

Foodmart connection

Postupným rozklikáváním hierarchie nalezneme databázi Foodmart, kterou máme právo prohledávat. Následně se přepneme do okna SQL, kde můžeme zkoušet připravené dotazy.

Na následujícím obrázku je nakresleno schéma databáze pro lepší orientaci v tabulkách databáze.

FoodMart Databaze

Jednoduché dotazy

Pro výběr dat slouží v SQL příkaz SELECT, jehož obecné schéma je:

SELECT sloupce

FROM tabulky

WHERE podmínky

GROUP BY spojit podle…

HAVING podmínky na skupiny

ORDER BY seřadit podle…

V této části se seznámíme s tučně označenými klauzulemi příkazu SELECT, tj. FROM, WHERE, ORDER BY. Příkazy budeme přímo zkoušet na databázi Foodmart. Uvedené příklady berte jako ukázky příkazů, vymyslete ke každému příkazu jiný podobný.

Vypracování je možné získat označením textu za slovem SELECT, napsáno bíle.

  1. Vypište celou tabulku zaměstnanců (skladu).
    • SELECT * FROM employee
  2. Vypište pouze sloupce first_name, last_name, birth_date z tabulky zaměstnanců.
    • SELECT first_name, last_name, birth_date FROM employee
  3. Vypište jména pozic zaměstnanců (sloupec position_title) tak, aby se žádnéjméno neopakovalo.
    • SELECT distinct position_title FROM employee
  4. Vypište přijmení zaměstnanců podle abecedy od a do z
    • SELECT distinct last_name FROM employee order by last_name asc
  5. Vypište přijmení zaměstnanců podle abecedy od z do a
    • SELECT distinct last_name FROM employee order by last_name desc
  6. Vypište jména a přijmení zaměstnanců a seřaďte je podle abecedy nejprve podle přijmení a pak podle jména
    • SELECT first_name, last_name FROM employee order by last_name, first_name
  7. Vypište pouze zaměstnance s platem větším než 40.000
    • SELECT * from employee where salary>40000
  8. Vyzkoušejte postupně další podmínky (=, >, <, >=, ⇐)
  9. Vypište pouze zaměstnance s platem mezi 10.000 a 20.000
    • SELECT * from employee where salary between 10000 and 20000
  10. Vyzkoušejte i složené podmínky s operátory AND, OR, NOT
  11. Vypište pouze zaměstnance jejichž přijmení začíná na S
    • SELECT * from employee where last_name like 'S%'
  12. Vypište pouze zaměstnance jejichž jméno končí na S a srovnejte je podle abecedy
    • SELECT * from employee where first_name like '%s' order by last_name
  13. Spojte tabulku zaměstnanců (employee) a tabulku skladů (store) a vypište všechny údaje.
    • SELECT * from store as s, employee as e where s.store_id=e.store_id
  14. Vypište všechny zaměstnance, kteří pracují v obchodu Store 1.
    • SELECT * from store as s, employee as e where s.store_id=e.store_id and store_name='Store 1'
  15. Spočítejte kolik takových zaměstnanců v databázi existuje.
    • SELECT count(*) from store as s, employee as e where s.store_id=e.store_id and store_name='Store 1'

Spojování tabulek pomocí JOIN

V předchozím cvičení je tabulka zaměstnanců (employee) a tabulku skladů (store) spojena pomocí podmínky v klazuli WHERE, což je nejjednodušší varianta spojení tabulek.

SELECT * from store, employee where store.store_id=employee.store_id

můžeme přepsat pomocí INNER JOIN

SELECT * from employee INNER JOIN store ON store.store_id=employee.store_id

Představme si, že existuje zaměstnanec, kterému zatím nebylo přiděleno pracoviště (nemá vyplněno store_id). Takový zaměstnanec nesplňuje podmínku pro spojení tabulek a proto vypadává z výsledné tabulky. To může být nežádoucí například v případě, že chceme vypsat všechny zaměstnance a jejich pracoviště (pokud zaměstnanec nemá pracoviště, chceme ho mít v seznamu s nevyplněným pracovištěm). Pro tento účel existují varianty JOIN - LEFT OUTER JOIN, RIGHT OUTER JOIN, FULL JOIN.

Příklady:

Vypíše všechny zaměstnance i ty, pro které neexistuje vazba do tabulky store.
SELECT * from employee LEFT OUTER JOIN store ON store.store_id=employee.store_id

Vypíše pouze zaměstnance, pro které existuje vazba do tabulky store, ale doplní i ty řádky z tabulky store, pro které neexistuje vazba do tabulky employee.
SELECT * from employee RIGHT OUTER JOIN store ON store.store_id=employee.store_id

Vypíše všechny zaměstnance a všechny řádky z tabulky store bez ohledu na vazbu mezi tabulkami.
SELECT * from employee FULL JOIN store ON store.store_id=employee.store_id

Dotazy s klauzulemi GROUP BY, HAVING

Pro výběr dat slouží v SQL příkaz SELECT:

SELECT sloupce

FROM tabulky

WHERE podmínky

GROUP BY spojit podle…

HAVING podmínky na skupiny

ORDER BY seřadit podle…

V této části se zaměříme na klauzule GROUP BY a HAVING. Doposud jsme pracovali s jednotlivými zaměstnanci. Často potřebujeme pracovat ne pouze s jednotlivými zaměstnanci, ale se skupinami zaměstnanců. Například v našem příkladě nás mohou zajímat skupiny zaměstnanců podle obchodu, ve kterém pracují (tabulka store). Vzhledem k tomu, že pracujeme se skupinou (množinou), nás budou zajímat tzv. agregované hodnoty - počet COUNT, průměr AVG, minimum MIN, maximum MAX, součet SUM pro zvolené skupiny. Například nás nezajímá věk jednoho konkrétního zaměstnance, ale zajímáme se o charakteristiku celé skupiny zaměstnanců, tedy o průměrný věk, nebo o nejnižší věk apod.

Vypracování je možné opět získat označením textu za slovem SELECT, napsáno bíle.

  1. Zjistěte počty zaměstnanců podle jejich profese (position_title).
    • SELECT position_title, count(*) FROM employee GROUP BY position_title ORDER BY position_title
  2. Zjistěte průměrné platy zaměstnanců podle profese, seřaďte podle průměrného platu vzestupně.
    • SELECT position_title, avg(salary) as avg FROM employee GROUP BY position_title ORDER BY avg
  3. Zjistěte průměrné platy zaměstnanců - mužů podle profese, seřaďte podle průměrného platu sestupně.
    • SELECT position_title, avg(salary) as avg FROM employee WHERE gender='M' GROUP BY position_title ORDER BY avg desc
  4. Zjistěte pro každý obchod (store) počet zaměstnanců, seřaďte podle jména obchodu.
    • SELECT store_name, count(*) FROM store as s, employee as e WHERE s.store_id=e.store_id GROUP BY store_name ORDER BY store_name
  5. Zjistěte jména obchodů s více jak 50 zaměstnanci.
    • SELECT store_name, count(*) as count FROM store as s, employee as e WHERE s.store_id=e.store_id GROUP BY store_name HAVING count(*)>50
  6. Zjistěte jména obchodů, kde pracuje více než 40 žen.
    • SELECT store_name, count(*) as count FROM store as s, employee as e WHERE s.store_id=e.store_id AND gender='F' GROUP BY store_name HAVING count(*)>40

Vnořené dotazy

V některých případech potřebujeme nejprve zjistit z databáze nějakou hodnotu, kterou následně použijeme v dotazu. Například chceme najít všechny zaměstnance obchodů s vyšším než průměrným platem. Nejprve musíme z databáze zjistit velikost průměrného platu: SELECT avg(salary) from employee. Výsledek následně použijeme pro hledání všech zaměstnanců, kteří mají plat vyšší než průměrný: SELECT * from employee where salary>(SELECT avg(salary) from employee)

  1. Zjistěte počet zaměstnanců, kteří měli nižší než je průměrný věk při nástupu do zaměstnání. Pomůcka: věk při nástupu do zaměstnání je (date_part('year',hire_date)-date_part('year',birth_date)).
    • SELECT count(*) FROM employee WHERE (date_part('year',hire_date)-date_part('year',birth_date))<(SELECT avg(date_part('year',hire_date)-date_part('year',birth_date)) FROM employee)

Studentské databáze

Změna hesla
ALTER USER jmeno WITH PASSWORD 'nove_heslo'

Zkušební databáze

SQL dotaz pro vytvoření databáze:

 CREATE SEQUENCE seq_sleva;
 CREATE TABLE sleva (
      id_sleva        int             NOT NULL UNIQUE DEFAULT nextval('seq_sleva'),
      nazev           varchar(64)     NOT NULL UNIQUE,
      sleva           numeric(2)      NOT NULL CHECK (sleva BETWEEN 0 AND 100),
      PRIMARY KEY (id_sleva));
GRANT USAGE ON SEQUENCE seq_sleva TO student_db12_00;
GRANT ALL PRIVILEGES ON TABLE sleva TO student_db12_00;
 CREATE SEQUENCE seq_zbozi;
 CREATE TABLE zbozi (
  id_zbozi            int             NOT NULL UNIQUE DEFAULT nextval('seq_zbozi'),
  nazev               varchar(128)    NOT NULL UNIQUE,
  popis               text,
  id_sleva            int             REFERENCES sleva ON UPDATE CASCADE ON DELETE SET NULL,
  cena                numeric(2)      CHECK (cena >0),
  PRIMARY KEY (id_zbozi));
 GRANT USAGE ON SEQUENCE seq_zbozi TO student_db12_00;
 GRANT ALL PRIVILEGES ON TABLE zbozi TO student_db12_00;
CREATE SEQUENCE seq_faktura;
CREATE TABLE faktura (
  id_faktura          int             NOT NULL UNIQUE DEFAULT nextval('seq_faktura'),
  odberatel           varchar(128)    NOT NULL,
  prodavac            varchar(64)     NOT NULL DEFAULT (user),
  PRIMARY KEY (id_faktura));
GRANT USAGE ON SEQUENCE seq_faktura TO student_db12_00;
GRANT ALL PRIVILEGES ON TABLE faktura TO student_db12_00;
CREATE TABLE fakturazbozi (
  id_faktura          int             NOT NULL REFERENCES faktura ON UPDATE CASCADE ON DELETE CASCADE,
  id_zbozi            int             NOT NULL REFERENCES zbozi ON UPDATE CASCADE ON DELETE CASCADE,
  id_sleva            int             REFERENCES sleva ON UPDATE CASCADE ON DELETE SET NULL,
  cena                numeric         NOT NULL,
  sleva               numeric(2),
  ks                  numeric         NOT NULL CHECK(ks>0),
  PRIMARY KEY (id_faktura,id_zbozi));
GRANT ALL PRIVILEGES ON TABLE fakturazbozi TO student_db12_00;

Vkládání dat

insert into sleva(nazev,sleva) VALUES ('AKCE: dnes 20%',20);
insert into sleva(nazev,sleva) VALUES ('TOTALNÍ VÝPRODEJ: 80%',80);
INSERT INTO zbozi(nazev,popis,id_sleva) VALUES ('ponožky modré','Krásné modré ponožky, co musíte mít',NULL);
INSERT INTO zbozi(nazev,popis,id_sleva) VALUES ('ponožky rudé','Kdo by nechěl tyto krásně rudé ponožky',1);
INSERT INTO zbozi(nazev,popis,id_sleva) VALUES ('ponožky děravé','druhá jakost, velká sleva',3);
INSERT INTO faktura (odberatel) VALUES ('Pepa Novák, Technická 8, Praha 6');
INSERT INTO faktura (odberatel) VALUES ('Pepina Nováková, Technická 18, Praha 6');
INSERT INTO faktura (odberatel) VALUES ('Pepina Nováková, Technická 18, Praha 6');
INSERT INTO fakturazbozi (id_faktura,ks,id_zbozi,id_sleva,cena,sleva)
      SELECT 1,10,id_zbozi,id_sleva,cena,sleva 
          FROM zbozi LEFT JOIN sleva USING (id_sleva)
          WHERE id_zbozi = 13;
INSERT INTO fakturazbozi (id_faktura,ks,id_zbozi,id_sleva,cena,sleva)
      SELECT 1,20,id_zbozi,id_sleva,cena,sleva 
          FROM zbozi LEFT JOIN sleva USING (id_sleva)
          WHERE id_zbozi = 14;
INSERT INTO fakturazbozi (id_faktura,ks,id_zbozi,id_sleva,cena,sleva)
      SELECT 2,10,id_zbozi,id_sleva,cena,sleva 
          FROM zbozi LEFT JOIN sleva USING (id_sleva)
          WHERE id_zbozi = 13;
INSERT INTO fakturazbozi (id_faktura,ks,id_zbozi,id_sleva,cena,sleva)
      SELECT 2,30,id_zbozi,id_sleva,cena,sleva 
          FROM zbozi LEFT JOIN sleva USING (id_sleva)
          WHERE id_zbozi = 15;
          
INSERT INTO fakturazbozi (id_faktura,ks,id_zbozi,id_sleva,cena,sleva)
      SELECT 3,100,id_zbozi,id_sleva,cena,sleva 
          FROM zbozi LEFT JOIN sleva USING (id_sleva)
courses/a4b33ds/cviceni-4-5.txt · Last modified: 2017/02/17 14:46 by komenant