Študent po absolvovaní predmetu ovláda princípy relačných databáz, je schopný aplikovať štandardné dátové modely, navrhovať relačné databázy a sformulovať filtračné dopyty.
Opýtajme sa umelej inteligencie
Študent po absolvovaní predmetu ovláda princípy relačných databáz, je schopný aplikovať štandardné dátové modely, navrhovať relačné databázy a sformulovať filtračné dopyty.
Študent po absolvovaní predmetu zvládne použitie náročnejších techník relačných databáz, teoretickú analýzu funkčných závislostí atribútov a je schopný pracovať s nerelačnými databázami.
Ukážky príkladov z prednášok a cvičení v zimnom semestri.
Portál DBS_Lab, kde budú aj domáce úlohy je implementovaný v MariaDB (mariadb.org). MariaDB vznikol ako fork (en.wikipedia.org) z MySQL (www.mysql.com), viac na MariaDB versus MySQL - Compatibility (mariadb.com).
MySQL je jedným z najpopulárnejších open-source RDBMS. Vďaka overenému výkonu, spoľahlivosti a jednoduchej použiteľnosti sa MySQL stal vedúcou voľbou pre webové aplikácie. Používajú ho významné webové služby ako sú Facebook, X, LinkedIn, Netflix, Airbnb, Booking.com, Uber, GitHub, YouTube a mnohé ďalšie. Ďalej sa využíva pre Content Management System (CMS) ako sú WordPress, Drupal, Joomla!, Contao, ...
root
. Bude ho potrebovať pre všetky administrátorské operácie.sudo systemctl status mysql
.3306
. Uistite sa, že tento port nie je obsadený inou aplikáciou.3306
.
Ukážky príkladov z prednášok a cvičení v zimnom i v letnom semestri.
Domáce úlohy v letnom semestri.
Microsoft SQL Server je robustný RDBMS pre profesionálnu prácu s dátami, ktorý ponúka viac možností ako MySQL a výbornú integráciu s Microsoft nástrojmi pre náročné podnikové prostredia. Používajú ho spoločnosti ako sú Morgan Stanley, John Deere, JPMorgan Chase, Accenture, Mastercard, KPMG, Infosys, Yahoo!, Dell, Nokia a mnohé ďalšie.
sa
) a aj Windows Authentication. Nastavte si silné heslo pre používateľa sa
.NAZOV_SERVERA\NAZOV_INSTANCIE
.1433
.R je programovací jazyk pre štatistické výpočty a vizualizáciu dát. RStudio je integrované vývojové prostredie (IDE), ktoré výrazne zjednodušuje prácu s R. Hoci R nie je priamo databázovým systémom, je to kľúčový nástroj pre dátových analytikov a vedcov, ktorí potrebujú pristupovať k dátam z databáz, analyzovať ich a vizualizovať.
install.packages("nazov_balicka")
na inštaláciu balíčkov. Bežné balíčky sú tidyverse
(pre prácu s dátami), gridExtra
(pre vizualizáciu grafov do mriežky), ggplot2
(pre vizualizáciu dát), RMySQL
alebo RODBC
(pre pripojenie a prácu s databázami).DBS1a/DBS | Študentov | A | B | C | D | E | FX |
---|---|---|---|---|---|---|---|
DBS1a | 983 | 12% | 11% | 19% | 22% | 30% | 6% |
DBS | 745 | 13% | 10% | 14% | 20% | 33% | 10% |
Plagiátorstvo nie je akceptovateľné. U poskytovateľa a samozrejme prijímateľa/plagiátora budú všetky doteraz získané body anulované. O danom incidente budú informovaní všetci kolegovia a daný prehrešok bude posunutý etickej komisii, ktorá môže rozhodnúť o vylúčení študenta zo štúdia.
Študujte kvôli sebe a pre seba... ...inak len mrháte svoj čas a čas iných. (K plagiátorstvu na PAZ1a)
Aktualizované: 24.9.2024
Aktualizované: 1.10.2024
Aktualizované: 15.10.2024
Aktualizované: 29.10.2024
Aktualizované: 5.11.2024
Aktualizované: 12.11.2024
Aktualizované: 27.11.2024
Aktualizované: 27.11.2024
Aktualizované: 3.12.2024
Aktualizované: 3.12.2024
Aktualizované: 14.3.2025
Aktualizované: 28.3.2025
Aktualizované: 26.2.2025
Aktualizované: 6.3.2025
Aktualizované: 15.5.2025
Prvý kontakt s databázovým systémom. Základné operácie nad databázou a tabuľkou.
Všetky dáta, ktoré vidíme v AiS2 sú uložené v databáze. Pomocou klikania a formulárov vieme modifikovať dané dáta - pridávať, mazať, aktualizovať. Napríklad vytvoriť zápis, zapisovať/odoberať si predmety, písať do fóra, prezerať si hodnotenia...
CHAR, VARCHAR, BOOLEAN, INTEGER, DECIMAL, DATE, ...
CREATE DATABASE [IF NOT EXISTS]
database_nameDROP DATABASE [IF EXISTS]
database_nameUSE
database_nameCREATE TABLE [IF NOT EXISTS]
table_name (
create_definition )
DROP TABLE [IF EXISTS]
table_nameINSERT [INTO]
table_name [(col_name [, col_name] ...)] VALUES
(
value_list )
[, (value_list)] ...SELECT * FROM
table_nameSHOW DATABASES
SHOW TABLES
[{FROM | IN} database_name]SHOW TABLES
a SELECT
.Majiteľ reštaurácie U vlka chce nalákať zákazníkov aj tým, že im bude zverejňovať denné menu na internete. Pomôžte mu splniť nasledujúce úlohy.
Navrhnite, vytvorte a naplňte tabuľku podľa nasledujúceho vzoru:
Dátum | Číslo objednávky | Gramáž | Jedlo | Cena | Dostupnosť |
---|---|---|---|---|---|
25.09.2025 | 1 |
150g | Kurací steak plnený syrom a suš. paradajkou, ryža, šalát (1,7) | 6.00€ |
|
25.09.2025 | 2 |
350g | Granatiersky pochod, kyslá uhorka (1) | 5.70€ |
|
26.09.2025 | 1 |
150g | Debrecínsky guľáš, kolienka (1,3) | 5.80€ |
|
26.09.2025 | 2 |
300g | Jablkovo- škoricové pirohy (1,3) | 4.70€ |
|
27.09.2025 | 1 |
150g | Hovädzí maďarský guľáš, domáca knedľa (1,7) | 5.80€ |
|
27.09.2025 | 2 |
Vyprážaný hermelín, listový šalát, hranolky, dresing (1,3,7) |
|
-- Jednoriadkovy komentar
# Jednoriadkovy komentar
/*
Viacriadkovy
komentar
*/
/*
SQL keywords are by default set to case insensitive that means that the keywords are allowed to be used in lower or upper case.
The names of the tables and columns specification are set to case insensitive on the SQL database server,
however, it can be enabled and disabled by configuring the settings in SQL.
*/
# Vytvorenie databazy
CREATE DATABASE restauracia_u_vlka;
-- Pouzitie databazy
USE restauracia_u_vlka;
/* Vytvorenie tabulky */
CREATE TABLE denne_menu
(
datum DATE,
cislo INTEGER, -- INT
gramaz INT, -- INTEGER
jedlo VARCHAR(300),
cena DEC(5,2), -- DECIMAL(5,2)
dostupnost BOOL -- BOOLEAN
);
# Vlozenie zaznamu do tabulky
INSERT INTO denne_menu VALUES ('2025-09-25', 1, 150, 'Kurací steak plnený syrom a suš. paradajkou, ryža, šalát (1,7)', 6, true);
-- Vlozenie viac zaznamov do tabulky
INSERT INTO denne_menu VALUES
("2025-09-25", 2, 350, 'Granatiersky pochod, kyslá uhorka (1)', 5.70, true),
('2025-09-26', 1, 150, "Debrecínsky guľáš, kolienka (1,3)", 5.80, true);
/* Vlozenie zaznamu do tabulky */
INSERT denne_menu VALUES ("2025-09-26", 2, 300, "Jablkovo- škoricové pirohy (1,3)", 4.70, false);
# Vlozenie zaznamu do tabulky
INSERT denne_menu(datum, cislo, gramaz, jedlo, cena, dostupnost)
VALUES ('2025-09-27', 1, 150, 'Hovädzí maďarský guľáš, domáca knedľa (1,7)', 5.80, NULL);
-- Vlozenie zaznamu do tabulky
INSERT denne_menu(datum, cislo, jedlo) VALUES ('2025-09-27', 2, 'Vyprážaný hermelín, listový šalát, hranolky, dresing (1,3,7)');
Vyberte/zobrazte/vypíšte obsah tabuľky.
Riešenie
/* Zobrazenie zaznamov z tabulky */
SELECT * FROM denne_menu;
Upravte skript z 1. zadania tak, aby sa dal použiť viackrát.
Riešenie
# Zmazanie databazy ak existuje
DROP DATABASE IF EXISTS restauracia_u_vlka;
# Vytvorenie databazy ak neexistuje
CREATE DATABASE IF NOT EXISTS restauracia_u_vlka;
-- Pouzitie databazy
USE restauracia_u_vlka;
/* Vytvorenie tabulky ak neexistuje */
CREATE TABLE IF NOT EXISTS denne_menu
(
datum DATE,
cislo INTEGER, -- INT
gramaz INT, -- INTEGER
jedlo VARCHAR(300),
cena DEC(5,2), -- DECIMAL(5,2)
dostupnost BOOL -- BOOLEAN
);
# Vlozenie zaznamu do tabulky
INSERT INTO denne_menu VALUES ('2025-09-25', 1, 150, 'Kurací steak plnený syrom a suš. paradajkou, ryža, šalát (1,7)', 6, true);
-- Vlozenie viac zaznamov do tabulky
INSERT INTO denne_menu VALUES
('2025-09-25', 2, 350, 'Granatiersky pochod, kyslá uhorka (1)', 5.70, true),
('2025-09-26', 1, 150, 'Debrecínsky guľáš, kolienka (1,3)', 5.80, true);
/* Vlozenie zaznamu do tabulky */
INSERT denne_menu VALUES ('2025-09-26', 2, 300, 'Jablkovo- škoricové pirohy (1,3)', 4.70, false);
# Vlozenie zaznamu do tabulky
INSERT denne_menu(datum, cislo, gramaz, jedlo, cena, dostupnost)
VALUES ('2025-09-27', 1, 150, 'Hovädzí maďarský guľáš, domáca knedľa (1,7)', 5.80, NULL);
-- Vlozenie zaznamu do tabulky
INSERT denne_menu(datum, cislo, jedlo) VALUES ('2025-09-27', 2, 'Vyprážaný hermelín, listový šalát, hranolky, dresing (1,3,7)');
Zobrazte zoznam tabuliek.
Riešenie
-- Zobrazenie tabuliek z aktualnej databazy
SHOW TABLES;
-- Zobrazenie tabuliek z konkretnej databazy
SHOW TABLES FROM restauracia_u_vlka;
Na tomto cvičení sme si prešli základný úvod do databázovým systémov a predstavili hodnotenie a program na celý semester. Prakticky sme si ukázali ako sa pripojiť k DBMS pomocou klientskeho nástroja, vytvorili sme svoju prvú databázu a tabuľku, definovali jej stĺpce s vhodnými dátovými typmi, vložili prvé dáta, ktoré sme si neskôr aj zobrazili. Tieto zručnosti sú kľúčové pre základnú prácu s databázovými systémami.
Výber dát pomocou SQL umožňuje rýchlo nájsť presne tie informácie, ktoré potrebujeme v obrovskom množstve údajov.
Všetky dáta, ktoré vidíme v AiS2 sú uložené v databáze. Dáta môžeme filtrovať a zoradiť podľa daných podmienok.
SELECT
DISTINCT
AS
ORDER BY
WHERE
+, -, *, /, %
=, >, <, >=, <=, <>, !=
IS NULL, IS NOT NULL
AND, OR, NOT, XOR
IN, NOT IN
BETWEEN, NOT BETWEEN
LIKE, NOT LIKE
%, _
SELECT
[ALL | DISTINCT | DISTINCTROW]
select_expr [, select_expr] ...
[FROM table_references]
[WHERE where_condition]
[ORDER BY {col_name | expr | position} [ASC | DESC], ... ]
SELECT * FROM table_name
, aby ste videli celú jej štruktúru a obsah.WHERE
klauzulách si najprv otestujte jednotlivé podmienky samostatne a potom ich kombinujte.NULL
predstavuje chýbajúci alebo neznámy údaj, ktorý sa správa špecificky a neporovnáva sa klasickými operátormi, ale operátormi IS NULL
a IS NOT NULL
.Dostali ste za úlohu spravovať databázu osôb. Importnite si ju a zoznámte sa s jej štruktúrou.
Na tomto cvičení sme si precvičili vertikálnu a horizontálnu (vo WHERE
pomocou rôznych operátorov) filtráciu dát, zoradiť dáta (ORDER BY
) a eliminovať duplicity (DISTINCT
).
Dôležitou súčasťou bola aj práca s NULL
hodnotami, ktoré predstavujú chýbajúce alebo neznáme údaje a neporovnávaju sa klasickými operátormi, ale operátormi IS NULL
a IS NOT NULL
.
Tieto zručností práce s dátami tvoria základ pri vyhľadávaní a analýze dát.
Regulárne výrazy a MySQL funkcie nám umožňujú efektívne filtrovať, upravovať a analyzovať dáta priamo v databáze, čím sa výrazne zvyšuje presnosť a flexibilita pri práci s údajmi.
V letnom semestri si ukážeme ako vytvoriť vlastné procedúry, funkcie a spúšťače.
Emaily, telefónne čísla, webové adresy, rodné čísla, predpisy platieb uvedené v správnom formáte/vzore. Zobrazenie dátumov v slovenskom formáte, celých mien aj s titulmi, výpočet váženého študijného priemeru...
NOT REGEXP
REGEXP
RLIKE
REGEXP_INSTR()
REGEXP_REPLACE()
REGEXP_SUBSTR()
REGEXP_LIKE()
- podpora len v MySQL, MariaDB nepodporujeCONCAT, REPLACE, UPPER, ...
PI, RAND, SQRT, ...
CURDATE, MONTHNAME, DATEDIFF, ...
CASE, CAST, COALESCE, ...
-- zobrazenie hodnoty systemovej premennej lc_time_names
SELECT @@lc_time_names;
-- en_US
-- sk_SK
-- nastavenie sk_SK
SET lc_time_names = 'sk_SK';
-- sk_SK
-- en_US
Dostali ste za úlohu spravovať databázu osôb. Importnite si ju a zoznámte sa s jej štruktúrou.
Skúste napísať regulárny výraz, ktorý vyhodnotí, či email bol napísaný v správnom formáte.
Riešenie
# Vrati 1 ak email je v spravnom formate, inak vrati 0.
SELECT 'lukas.mino@upjs.sk' REGEXP '^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$';
-- alebo
SELECT 'lukas.mino@upjs.sk' RLIKE '^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$';
-- alebo
SELECT REGEXP_LIKE('lukas.mino@upjs.sk', '^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$');
-- Vrati 0
SELECT 'lukas,mino@upjs.sk' REGEXP '^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$';
Skúste na príklade ukázať rozdiel medzi funkciami NOW
a SYSDATE
.
SELECT NOW(); #vrati cas spustenia dopytu
SELECT SYSDATE(); #vrati cas kedy bola zavolana funkcia
-- Pozn.: CURRENT_TIMESTAMP a NOW vratia cas zaciatku vykonavania dopytu. Naproti tomu SYSDATE vrati aktualny cas. Vid. priklady:
-- Cas oboch volani NOW je rovnaky.
SELECT NOW(), SLEEP(2), NOW();
-- Cas druheho volania SYSDATE je posunuty o dve sekundy.
SELECT SYSDATE(), SLEEP(2), SYSDATE();
Zobrazte dnešný deň v týždni po slovensky.
Riešenie
-- Den v tyzdni
-- zobrazenie systemovej premennej lc_time_names
SELECT @@lc_time_names;
-- en_US
-- nastavenie po slovensky
SET lc_time_names = 'sk_SK';
SELECT DAYNAME(CURRENT_DATE()) slov;
-- nastavenie po anglicky
SET lc_time_names = 'en_US';
SELECT DAYNAME(CURRENT_DATE()) ang;
-- alebo
SELECT
CASE WEEKDAY(CURRENT_DATE()) -- 0 = Monday
WHEN 0 THEN 'Pondelok'
WHEN 1 THEN 'Utorok'
WHEN 2 THEN 'Streda'
WHEN 3 THEN 'Stvrtok'
WHEN 4 THEN 'Piatok'
WHEN 5 THEN 'Sobota'
WHEN 6 THEN 'Nedela'
ELSE 'Nezname'
END 'Deň v týždni'
FROM osoba;
-- alebo
SELECT
CASE
WHEN DAYOFWEEK(CURRENT_DATE()) = 1 THEN 'Nedela' -- 1 = Sunday
WHEN DAYOFWEEK(CURRENT_DATE()) = 2 THEN 'Pondelok'
WHEN DAYOFWEEK(CURRENT_DATE()) = 3 THEN 'Utorok'
WHEN DAYOFWEEK(CURRENT_DATE()) = 4 THEN 'Streda'
WHEN DAYOFWEEK(CURRENT_DATE()) = 5 THEN 'Stvrtok'
WHEN DAYOFWEEK(CURRENT_DATE()) = 6 THEN 'Piatok'
WHEN DAYOFWEEK(CURRENT_DATE()) = 7 THEN 'Sobota'
ELSE 'Nezname'
END 'Deň v týždni'
FROM osoba;
Na tomto cvičení sme si precvičili prácu s regulárnymi výrazmi v SQL, ktoré nám umožnili vyhľadávať a filtrovať údaje podľa komplexnejších textových vzorov. Taktiež sme využili rôzne funkcie na spracovanie a transformáciu dát ako sú funkcie na prácu s reťazcami, číslami a dátumami. Okrem toho sme sa oboznámili aj s inými špecifickými funkciami, ako sú systémové (napr. informácie o verzii databázy, používateľoch, rôznych nastaveniach a stave systému), podmienené (CASE, IF) a rôzne iné. Cieľom bolo ukázať, ako možno priamo v databáze efektívne analyzovať a pripravovať dáta bez nutnosti ďalšieho spracovania v externých nástrojoch.
Pre získanie ucelených informácií je často potrebné spájať dáta z viacerých tabuliek. Spojenie tabuliek nám umožňuje získať ucelený pohľad na prepojené dáta z viacerých zdrojov, čo je nevyhnutné pre komplexnejšie analýzy. Agregačné funkcie nám pomáhajú rýchlo zhrnúť a vyhodnotiť veľké množstvo údajov, napríklad spočítať počet záznamov, priemer či celkový súčet.
V letnom semestri si ukážeme ako analyzovať a optimalizovať dopyty pomocou relačnej algebry a indexov. Na pokročilejšiu a efektívnejšiu analýzu dát si ukážeme prácu s WINDOW funkciami a kontingenčnými (PIVOT) tabuľkami.
Vačšina zobrazených dát hlavne v tabuľkách vznikajú spojením desiatok tabuliek. Štatistické dáta vznikajú pomocou agregačných funkcií, napríklad počty študentov zapísaných na jednotlivé cvičenia, počet odučených hodín, počet prihlásených a prijatých uchádzačov z jednotlivých krajín v daných rokoch, trend úspešnosti študentov na jednotlivých predmetoch za posledné roky, miera obsadenosti internátov jednotlivých fakúlt, zoradenie študentov podľa váženého študijného priemeru pre jednotlivé odbory alebo fakulty, zobrazenie posledného udeleného hodnotenia pri opakovaných skúškach, ...
CROSS JOIN
[INNER] JOIN
LEFT [OUTER] JOIN
RIGHT [OUTER] JOIN
FULL [OUTER] JOIN
- MySQL nepodporujeSTRAIGHT_JOIN
- ako INNER JOIN, ale vynúti poradie tabuliekNATURAL [INNER | {LEFT|RIGHT} [OUTER]] JOIN
- join podľa rovnakých názvov stĺpcovSELF JOIN
- join tej istej tabuľky na sebaSEMI JOIN
- vracia riadky z A, ak existuje zhoda v B (bez duplikácie) - MySQL nepodporuje, ale napr. MS SQL Server ánoANTI JOIN
- vracia riadky z A, ktoré nemajú zhodu v B (napr. NOT EXISTS) - MySQL nepodporuje, ale napr. MS SQL Server ánoLOOP | HASH | MERGE | REMOTE | REDUCE | REPLICATE | REDISTRIBUTE [(columns count)] JOIN
- MySQL nepodporuje, ale napr. MS SQL Server ánoParallel Join
- join rozdelený medzi viacero vlákien - MySQL nepodporuje, ale napr. MS SQL Server ánoMaterialized Join
- jedna strana joinu je v dočasnej tabuľkeMIN, MAX, COUNT, SUM, AVG, ...
GROUP BY
GROUP BY ... WITH ROLLUP
HAVING
SELECT
[ALL | DISTINCT | DISTINCTROW]
select_expr [, select_expr] ...
[FROM
table_name [[AS] alias]
[ {[INNER | CROSS] JOIN | STRAIGHT_JOIN} table_name [[AS] alias] {ON search_condition | USING (join_column_list)}
| {LEFT|RIGHT} [OUTER] JOIN table_name [[AS] alias] {ON search_condition | USING (join_column_list)}
| NATURAL [INNER | {LEFT|RIGHT} [OUTER]] JOIN table_name [[AS] alias]
]
...
]
[WHERE where_condition]
[GROUP BY {col_name | expr | position}, ... [WITH ROLLUP]]
[HAVING having_condition]
[ORDER BY {col_name | expr | position} [ASC | DESC], ... ]
-- zobrazenie hodnoty systemovej premennej sql_mode
SELECT @@sql_mode;
-- ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION
-- zobrazenie hodnoty systemovej premennej session.sql_mode
SELECT @@session.sql_mode;
-- ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION
-- nastavenie ONLY_FULL_GROUP_BY
SET SESSION sql_mode = 'ONLY_FULL_GROUP_BY';
-- alebo
SET GLOBAL sql_mode = 'ONLY_FULL_GROUP_BY';
-- alebo
SET SESSION sql_mode = sys.list_add(@@session.sql_mode, 'ONLY_FULL_GROUP_BY');
-- zrusenie ONLY_FULL_GROUP_BY
SET SESSION sql_mode = (SELECT REPLACE(@@sql_mode,'ONLY_FULL_GROUP_BY',''));
Po úspešnom absolvovaní predchádzajúcich týždoch Vás presunuli na medicínsky projekt. Dostali ste za úlohu spravovať databázu polikliniky. Importnite si ju a zoznámte sa s jej štruktúrou.
Importnite si databázu Mnoziny2 a zoznámte sa s jej štruktúrou. Zobrazte výsledky spojenia dvoch tabuliek T1 a T1 cez stĺpec x pomocou CROSS JOIN, INNER JOIN, LEFT OUTER JOIN, RIGHT OUTER JOIN.
USE mnoziny2;
-- CROSS JOIN
SELECT * FROM T1 CROSS JOIN T2;
-- alebo
SELECT * FROM T1, T2;
-- CROSS JOIN spojením tabuliek cez stĺpec x
SELECT * FROM T1 CROSS JOIN T2 WHERE T2.x = T1.x;
-- alebo
SELECT * FROM T1, T2 WHERE T2.x = T1.x;
-- NEEFEKTIVNE, radsej pouzit INNER JOIN
-- INNER JOIN
SELECT * FROM T1 INNER JOIN T2 ON T2.x = T1.x;
-- alebo
SELECT * FROM T1 JOIN T2 ON b.x = T1.x;
-- alebo
SELECT * FROM T1 JOIN T2 USING(x);
-- LEFT OUTER JOIN
SELECT * FROM T1 LEFT OUTER JOIN T2 ON T2.x = T1.x;
-- alebo
SELECT * FROM T1 LEFT JOIN b ON T2.x = T1.x;
-- alebo
SELECT * FROM T1 LEFT OUTER JOIN T2 USING(x);
-- alebo
SELECT * FROM T1 LEFT JOIN T2 USING(x);
-- RIGHT OUTER JOIN
SELECT * FROM T1 RIGHT OUTER JOIN T2 ON T2.x = T1.x;
-- alebo
SELECT * FROM T1 RIGHT JOIN T2 ON T2.x = T1.x;
-- alebo
SELECT * FROM T1 RIGHT OUTER JOIN T2 USING(x);
-- alebo
SELECT * FROM T1 RIGHT JOIN T2 USING(x);
Importnite si databázu Mnoziny2 a zoznámte sa s jej štruktúrou. Zobrazte výsledky spojenia dvoch tabuliek a a b cez stĺpec x pomocou FULL OUTER JOIN.
USE mnoziny2;
-- FULL OUTER JOIN MySQL zatial nepodporuje
SELECT * FROM T1 FULL OUTER JOIN T2 WHERE T2.x = T1.x;
-- Simulacia spojenia cez FULL OUTER JOIN
SELECT * FROM T1 LEFT OUTER JOIN T2 ON T2.x = T1.x
UNION
SELECT * FROM T1 RIGHT JOIN T2 ON T2.x = T1.x;
V ďalšich zadaniach budete pracovať s databázou poliklinika.
Zobrazte meno pacienta, ktorý ma najväčší mesačný príjem.
-- Meno pacienta, ktory ma najvacsi mesacny prijem
SELECT
krstne
FROM pacienti
WHERE mesPrijem = (SELECT MAX(mesPrijem) FROM pacienti);
Zobrazte mininimálny, maximálny, počet, sumu a priemerný poplatok pacientov u jednotlivých lekárov.
-- Informacie o poplatkoch pacientov u lekarov
SELECT
idP Pacient,
idL Lekar,
MIN(poplatok) 'Minimálny poplatok',
MAX(poplatok) 'Maximálny poplatok',
COUNT(poplatok) 'Počet poplatkov',
SUM(poplatok) 'Suma poplatkov',
AVG(poplatok) 'Priemer poplatkov',
FROM navstevy
GROUP BY idP, idL
ORDER By idP, idL;
-- alebo
SELECT
idP Pacient,
idL Lekar,
MIN(poplatok) 'Minimálny poplatok',
MAX(poplatok) 'Maximálny poplatok',
COUNT(poplatok) 'Počet poplatkov',
SUM(poplatok) 'Suma poplatkov',
AVG(poplatok) 'Priemer poplatkov',
FROM navstevy
GROUP BY idL, idP
ORDER By idP, idL;
Zobrazte mininimálny, maximálny, počet, sumu a priemerný poplatok pacientov u jednotlivých lekárov. Zobrazte meno pacienta a meno lekára.
-- Informacie o poplatkoch pacientov u lekarov s menami pacientov a lekarov
SELECT
P.krstne Pacient,
L.krstne Lekar,
MIN(poplatok) 'Minimálny poplatok',
MAX(poplatok) 'Maximálny poplatok',
COUNT(poplatok) 'Počet poplatkov',
SUM(poplatok) 'Suma poplatkov',
AVG(poplatok) 'Priemer poplatkov',
FROM navstevy N
JOIN pacienti P ON P.idP = N.idP
JOIN lekari L ON L.idL = N.idL
GROUP BY N.idP, P.krstne, N.idL, L.krstne -- co ak sa dvaja pacienti/lekari volaju rovnako?
ORDER By N.idP, N.idL;
Zobrazte id pacientov, ktorí mali viac ako 1 návštevu. Uveďte id pacienta a počet návštev. Výsledok zoraďte podľa najväčšieho počtu návštev a potom podľa id pacientov.
-- id pacientov a pocet navstev, ktori mali viac ako 1 navstevu
SELECT
idP,
COUNT(idN) 'Počet návštev'
FROM navstevy
GROUP BY idP
HAVING COUNT(idN) > 1
ORDER BY 2 DESC, idP ASC;
-- alebo
SELECT
idP,
COUNT(*) 'Počet návštev'
FROM navstevy
GROUP BY idP
HAVING COUNT(*) > 1
ORDER BY COUNT(*) DESC, 1;
Zistite koľko zarobili jednotliví lekári. Vo výsledku chceme vidieť aj koľko zarobili dokopy.
SELECT
CASE WHEN l.krstne IS NULL THEN 'Spolu' ELSE l.krstne END krstne,
SUM(n.poplatok) as prijem
FROM navstevy n
JOIN lekari l ON l.idL = n.idL
GROUP BY l.krstne
WITH ROLLUP;
Na tomto cvičení sme sa naučili spájať tabuľky a rozlišovať rôzne typy spájania,
napr.
INNER JOIN
pre získanie dát, ktoré majú zhodu (v klauzule ON
) v oboch tabuľkách,
LEFT OUTER JOIN
pre zachovanie všetkých dát z ľavej tabuľky,
RIGHT OUTER JOIN
pre zachovanie všetkých dát z pravej tabuľky,
FULL OUTER JOIN
pre zachovanie všetkých dát z oboch tabuliek, ...
Taktiež sme sa naučili sumarizovať dáta pomocou agregačných funkcií,
pochopili sme význam klauzuly GROUP BY
pre zoskupovanie dát
a použitie klauzuly HAVING
na filtrovanie zoskupených dát.
Takto dokážeme získavať komplexne informácie z viacerých súvisiacich tabuliek, získavať štatistické prehľady a analyzovať dáta.
Vhodný návrh databázovej štruktúry je základom pre rýchlu, spoľahlivú a prehľadnú prácu s údajmi, vďaka čomu sa dáta ľahko spravujú, rozširujú a analyzujú.
V letnom semestri si ukážeme pomocou normálnych foriem proces eliminovania duplicitných údajov, ktorý vedie k zlepšeniu integrity dát.
Aktuálne databáza AiS2 obsahuje 2478 používateľských tabuliek. Preto je vhodná databázová štruktúra veľmi dôležitá - zaručuje prehľadnosť a zrozumiteľnosť, integritu a konzistenciu dát, eliminuje duplicity, optimalizuje výkonnosť a škálovateľnosť, zlepšuje údržbu a rošíriteľnosť, uľahčuje auditovanie a logovanie prístupu k citlivým dátam, taktiež umožňuje jednoduchšie používať ORM nástroje, ETL procesy, zálohovanie či monitorovanie výkonnosti.
Dostali ste za úlohu navrhnúť databázovú štruktúru na sprevádzkovanie eshopu.
Navrhnite vhodnú databázovú štruktúru na sprevádzkovanie eshopu.
Na tomto cvičení sme sa snažili vhodne návrhnúť databázovú štruktúru a oboznámili sme sa s princípmi modelovania dát a dôležitosťou správne navrhnutých tabuliek pre efektívne a spoľahlivé spracovanie údajov. Precvičili sme si identifikáciu entít a ich vzťahov, tvorbu ER diagramov a transformáciu modelu do relačnej podoby. Správny návrh databázovej štruktúry je kľúčový preto, lebo ovplyvňuje nielen výkon a rýchlosť spracovania dát, ale aj spoľahlivosť, konzistenciu a jednoduchosť budúcej údržby systému. Umožňuje zároveň ľahšie rozširovanie a integráciu databázy pri meniacich sa požiadavkách, čím šetrí čas aj náklady v praxi.
Modifikácia dát a metadát nám umožňuje udržiavať databázu aktuálnu a prispôsobovať ju meniacim sa požiadavkám bez nutnosti jej úplného prebudovania. Integritné obmedzenia zabezpečujú konzistenciu dát, čím chránia databázu pred chybami a nekorektnými údajmi.
V letnom semestri budeme vytvárať spúšťače (TRIGGER), ktoré zautomatizujú reakcie na zmeny v databáze, vďaka čomu môžeme zabezpečiť konzistenciu dát, zaznamenávať dôležité udalosti alebo vykonávať kontroly dát bez manuálneho zásahu.
Napríklad zapísaním študenta na predmet musíme cez integritné obmedzenia zabezpečiť:
INSERT, INSERT INTO SELECT, UPDATE, DELETE
ALTER TABLE
ADD | ALTER | DROP | CHANGE | MODIFY | RENAME COLUMN
ADD | ALTER | DROP [CONSTRAINT [symbol]] PRIMARY KEY | UNIQUE | FOREIGN KEY | CHECK
ON DELETE RESTRICT | CASCADE | SET NULL | NO ACTION | SET DEFAULT
ON UPDATE RESTRICT | CASCADE | SET NULL | NO ACTION | SET DEFAULT
-- vypnutie safe modu, aby sa dalo aktualizovat/mazat podla lubovolnej podmienky
SET SQL_SAFE_UPDATES = 0;
-- zapnutie safe modu, aby sa dalo aktualizovat/mazat len podla kluca
SET SQL_SAFE_UPDATES = 1;
Integritné obmedzenia sú mechanizmy, ktoré zabezpečujú správnosť, konzistenciu a logickú platnosť údajov v databáze.
Na cvičení sme si zdôraznili ich úlohu pri ochrane databázy pred chybnými alebo nekonzistentnými dátami,
napríklad prostredníctvom PRIMARY KEY
, FOREIGN KEY
, UNIQUE
, NOT NULL
, DEFAULT
či CHECK
podmienok.
Správne definované integritné obmedzenia výrazne zjednodušujú správu databázy, zvyšujú jej spoľahlivosť a minimalizujú potrebu dodatočných kontrol na aplikačnej úrovni.
Okrem toho sme si prakticky vyskúšali aj modifikáciu metadát existujúcej databázy,
napríklad úpravou štruktúry tabuliek alebo dopĺňanie nových obmedzení, pričom sme si overili, ako tieto zmeny vplývajú na konzistenciu dát.
Ďalej sme sa naučili ako kopírovať dáta z jednej tabuľky do druhej a ako dáta nielen vkladať, ale aj aktualizovať a mazať.
Pri aktualizácii a mazaní dát sme pochopili dôležitosť klauzuly WHERE
, čo je nevyhnutné pre zachovanie integrity dát v databáze.
Množinové operácie nám umožňujú efektívne porovnávať a kombinovať výsledky viacerých dopytov, čo zjednodušuje prácu s podobnými alebo rozdielnymi dátami. Vnorené dopyty zasa dávajú možnosť riešiť zložitejšie problémy krok po kroku, pričom výsledok jedného dopytu slúži ako vstup pre ďalší, čo výrazne rozširuje možnosti analýzy údajov.
V letnom semestri predstavíme WINDOW funkcie, ktoré síce nie sú úplnou náhradou za vnorené dopyty, ale v mnohých analytických úlohách môžu dané dopyty zjednodušiť a zrýchliť.
UNION
INTERSECT
EXCEPT
=, >, <, >=, <=, <>, !=
IN, NOT IN
ANY, SOME
ALL
EXISTS, NOT EXISTS
Importnite si databázu množiny a zoznámte sa s jej štruktúrou. Zobrazte výsledky zjednotenia tabuliek a a b.
USE mnoziny;
-- Zjednotenie bez opakovania
SELECT x, y FROM a
UNION -- Zjednotenie bez opakovania
SELECT x, y FROM b;
Zobrazte výsledky zjednotenia tabuliek a a b tak, aby sa riadky mohli opakovať.
USE mnoziny;
-- Zjednotenie s opakovanim
SELECT x, y FROM a
UNION ALL -- Zjednotenie s opakovanim
SELECT x, y FROM b;
Zobrazte výsledky prieniku tabuliek a a b.
USE mnoziny;
-- Prienik
-- Prienik pomocou INTERSECT (od verzie 8.0.31)
SELECT x, y FROM a
INTERSECT
SELECT x, y FROM b;
-- Prienik pomocou INTERSECT (od verzie 8.0.31)
TABLE a INTERSECT TABLE b;
-- Prienik pomocou IN
SELECT x, y
FROM a
WHERE (x, y) IN (SELECT x, y FROM b);
-- Prienik pomocou ANY
SELECT x, y
FROM a
WHERE (x, y) = ANY (SELECT x, y FROM b);
-- Prienik pomocou SOME
SELECT x, y
FROM a
WHERE (x, y) = SOME (SELECT x, y FROM b);
-- Prienik pomocou EXISTS
SELECT x, y
FROM a
WHERE EXISTS (SELECT * FROM b WHERE b.x = a.x AND b.y = a.y);
-- Prienik pomocou INNER JOIN
SELECT a.x, a.y
FROM a
JOIN b ON b.x = a.x AND b.y = a.y;
-- Prienik pomocou INNER JOIN
SELECT DISTINCT a.x AS x, a.y AS y
FROM a
INNER JOIN b USING (x,y);
-- Prienik pomocou NATURAL JOIN
SELECT x, y
FROM a
NATURAL JOIN b;
Zobrazte výsledky rozdielu tabuliek a a b.
USE mnoziny;
-- Rozdiel
-- Rozdiel pomocou EXCEPT (od verzie 8.0.31)
SELECT x, y FROM a
EXCEPT
SELECT x, y FROM b;
-- Rozdiel pomocou EXCEPT (od verzie 8.0.31)
TABLE a EXCEPT TABLE b;
-- Rozdiel pomocou NOT IN
SELECT x, y
FROM a
WHERE (x, y) NOT IN (SELECT x, y FROM b);
-- Rozdiel pomocou ALL
SELECT x, y
FROM a
WHERE (x, y) <> ALL (SELECT x, y FROM b);
-- Rozdiel pomocou NOT EXISTS
SELECT x, y
FROM a
WHERE NOT EXISTS (SELECT * FROM b WHERE b.x = a.x AND b.y = a.y);
-- Rozdiel pomocou LEFT OUTER JOIN
SELECT a.x, a.y
FROM a
LEFT OUTER JOIN b ON b.x = a.x AND b.y = a.y
WHERE b.x IS NULL;
-- Rozdiel pomocou LEFT OUTER JOIN
SELECT DISTINCT a.x AS x, a.y AS y
FROM a
LEFT OUTER JOIN b USING (x,y)
WHERE b.x IS NULL;
Z databázy Poliklinika zobrazte všetky mená pacientov a lekárov. Mená sa môžu opakovať. Výsledok zoraďte lexikograficky.
USE poliklinika;
SELECT krstne FROM pacienti
UNION ALL
SELECT krstne FROM lekari
ORDER BY krstne;
Zobrazte všetky mená pacientov a lekárov tak, aby sa mená neopakovali. Výsledok zoraďte lexikograficky.
SELECT krstne FROM pacienti
UNION
SELECT krstne FROM lekari
ORDER BY krstne;
Zobrazte rovnaké mená pacientov a lekárov. Výsledok zoraďte lexikograficky.
-- Prienik
-- Prienik pomocou INTERSECT (od verzie 8.0.31)
SELECT krstne FROM pacienti
INTERSECT
SELECT krstne FROM lekari
ORDER BY krstne;
-- Prienik pomocou IN
SELECT krstne
FROM pacienti
WHERE krstne IN (SELECT krstne FROM lekari)
ORDER BY krstne;
-- Prienik pomocou ANY
SELECT krstne
FROM pacienti
WHERE krstne = ANY (SELECT krstne FROM lekari)
ORDER BY krstne;
-- Prienik pomocou SOME
SELECT krstne
FROM pacienti
WHERE krstne = SOME (SELECT krstne FROM lekari)
ORDER BY krstne;
-- Prienik pomocou EXISTS
SELECT krstne
FROM pacienti
WHERE EXISTS (SELECT krstne FROM lekari WHERE lekari.krstne = pacienti.krstne)
ORDER BY krstne;
-- Prienik pomocou CROSS JOIN
SELECT p.krstne
FROM pacienti p, lekari l
WHERE p.krstne = l.krstne
-- Prienik pomocou CROSS JOIN
SELECT p.krstne
FROM pacienti p CROSS JOIN lekari l
WHERE p.krstne = l.krstne
-- Prienik pomocou JOIN
SELECT p.krstne
FROM pacienti p JOIN lekari l ON p.krstne = l.krstne
Zobrazte len mená lekárov, ktorých mená neobsahujú mená pacientov. Výsledok zoraďte lexikograficky.
-- Rozdiel
-- Rozdiel pomocou EXCEPT (od verzie 8.0.31)
SELECT krstne FROM lekari
EXCEPT
SELECT krstne FROM pacienti
ORDER BY krstne;
-- Rozdiel pomocou NOT IN
SELECT krstne
FROM lekari
WHERE krstne NOT IN (SELECT krstne FROM pacienti)
ORDER BY krstne;
-- Rozdiel pomocou ALL
SELECT krstne
FROM lekari
WHERE krstne <> ALL (SELECT krstne FROM pacienti)
ORDER BY krstne;
-- Rozdiel pomocou NOT EXISTS
SELECT krstne
FROM lekari
WHERE NOT EXISTS (SELECT krstne FROM pacienti WHERE pacienti.krstne = lekari.krstne)
ORDER BY krstne;
-- Rozdiel pomocou LEFT OUTER JOIN
SELECT p.krstne
FROM pacienti p
LEFT OUTER JOIN lekari l ON p.krstne = l.krstne
WHERE l.idL IS NULL;
Pridajte stĺpec poradie k pacientom, kde tento stĺpec bude reprezentovať lexikografické poradie krstných mien v abecede.
SELECT
(SELECT COUNT(*) + 1 from pacienti x WHERE x.krstne < p.krstne) poradie,
p.*
FROM pacienti p;
Zobrazte rôzne krstné pacientov, ktorí navštívili daného lekára viac ako raz.
SELECT DISTINCT p.krstne FROM
(
SELECT idP, idL, COUNT(*) pocet
FROM navstevy
GROUP BY idP, idL
) AS T -- alias stlpca je potrebny
JOIN pacienti p ON p.idP = T.idP
WHERE T.pocet > 1;
Nájdite údaje o pacientoch, ktorí májú druhý najmenší mesačný príjem.
-- Pomocou MIN
SELECT
p.*
FROM
pacienti p
WHERE
p.mesPrijem =
(
SELECT
MIN(p2.mesPrijem)
FROM
pacienti p2
WHERE
p2.mesPrijem >
(
SELECT
MIN(p1.mesPrijem)
FROM
pacienti p1
WHERE
p1.mesPrijem IS NOT NULL
)
);
-- Pomocou ALL
SELECT
T.*
FROM
(
SELECT p3.* FROM pacienti p3
WHERE p3.mesPrijem >
(
SELECT p2.mesPrijem FROM Pacienti p2
WHERE p2.mesPrijem <= ALL
(
SELECT p1.mesPrijem FROM Pacienti p1
WHERE p1.mesPrijem IS NOT NULL
)
)
) T
WHERE
T.mesPrijem <= ALL
(
SELECT p3.mesPrijem FROM Pacienti p3 -- 7
WHERE p3.mesPrijem >
(
SELECT p2.mesPrijem FROM Pacienti p2 -- 1
WHERE p2.mesPrijem <= ALL
(
SELECT p1.mesPrijem FROM Pacienti p1 -- 8
WHERE p1.mesPrijem IS NOT NULL
)
)
);
Na tomto cvičení sme si precvičili kombinovanie a porovnávanie dát z viacerých tabuliek pomocou operácií ako UNION
, INTERSECT
a EXCEPT
.
Zároveň sme si osvojili princípy vnorených dopytov, ktoré umožňujú efektívne získavať údaje na základe výsledkov iných dopytov.
Taktiež sme pochopili, ako tieto techniky umožňujú riešiť komplexnejšie analytické úlohy priamo v databáze a tak zvyšovať flexibilitu a presnosť pri práci s dátami.
Tieto techniky sú nevyhnutné pre riešenie zložitejších analytických úloh.
V zimnom semestri sme sa naučili navrhovať relačné databázové štruktrúry a pracovať s relačnými databázami pomocou SQL.
V letnom semestri použijeme aj vlastné a pokročilejšie techniky v relačných databázach, budeme vedieť analyzovať a optimalizovať dopyty, eliminovať duplicitné údaje a zlepšiť integritu dát. Okrem relačných modelov ukážeme aj prácu s inými modelmi v prostredí SQL. Taktiež budeme vedieť pracovať aj s nerelačnými databázami.
Vedieť iba základy SQL vo vývoji AiS2 nestačí. Bežne prichádzajú požiadavky, kde je potrebné použiť aj pokročilejšie techniky ako vlastné procedúry, funkcie, TRIGGER, WINDOW funkcie, VIEW, CTE, CURSOR, .... eliminovať duplicity a optimalizovať dopyty.
SHOW, INFORMATION_SCHEMA
ROLLUP
, CUBE
TEMPORARY TABLE
TRUNCATE TABLE
GENERATED ALWAYS
INSERT IGNORE INTO
REPLACE [INTO]
CHARACTER SET, COLLATION, COLLATE
MyISAM, InnoDB, MERGE, MEMORY (HEAP), ARCHIVE, CSV, FEDERATED
Integrácia MySQL s prostredím R umožňuje efektívne kombinovať výkonnosť relačných databáz s pokročilými štatistickými a vizualizačnými nástrojmi dostupnými v R.
Na tomto cvičení sme si osvojili spôsoby ako sa pripojiť k databáze MySQL priamo z prostredia R, načítať a filtrovať dáta nieln pomocou SQL dopytov, ale aj pomocou nástroja R a následne ich analyzovať a vizualizovať pomocou štatistických a grafických nástrojov R. Precvičili sme si integráciu databázových operácií s analytickými funkcionalitami R, čím sme získali skúsenosti s efektívnym spracovaním, transformáciou a reprezentáciou dát.
Relačná algebra predstavuje formálny jazyk operácií nad relačnými dátami, ktorý slúži ako teoretický základ pre optimalizáciu dopytov a pochopenie interného spracovania údajov v databázových systémoch. Normalizácia predstavuje proces k návrhu databázových štruktúr, ktorého cieľom je eliminácia nadbytočnosti (redundantnosti), zabezpečenie integritných pravidiel a zlepšenie konzistencie dát.
Viac sa týmto témam budeme venovať v letnom semestri.
Informácie o projekte dostanete na predmete PAZ1c, viac informácií nájdete na paz1c.ics.upjs.sk:
Zástupca (-ovia) tímu predstavia databázový a triedový návrh svojho projektu učiteľovi. Ideálne je použitie UML a ER diagramov. Očakáva sa aj zoznam okien s predpokladanou funkcionalitou.
Predstavenie návrhu projektu slúži ako skorá spätná väzba, aby sa predišlo návrhovým chybám, príliš jednoduchým, alebo naopak príliš komplikovaným návrhom,
ktoré by mohli predstavovať riziko vytvorenia slabo ohodnoteného projektu.
Pri predstavovaní návrhu bude prítomný aj cvičiaci predmetu Databázové systémy a za návrh môže udeľovať body pre jeho predmet.
Informácie o projekte dostanete na prednáške DBS.
Obhajoba návrhu projektu bude prebiehať mimo rozvrhu hodín.
Riešenie projektu pozostáva z nasledujúcich úloh:
Návrh entitno-relačného diagramu nie je jednoduchý - nezúfajte a poučte sa z chýb!
Uveďte základné pojmy v oblasti databázových systémov (DBS). Ako prebieha vytvorenie databázového systému, návrh dátových a programových štruktúr potrebných na zabezpečenie základných funkcií DBS? Ako prebieha zabezpečenie konzistencie dát? Ako je možné databázové štruktúry modelovať?
Popíšte algoritmický problém usporiadania, základné algoritmy a ich zložitosť. Aké je dolné ohraničenie zložitosti algoritmov usporiadania porovnávaním? Uveďte príklad na algoritmus usporiadania, ktorý neporovnáva prvky. Aká je podpora triedenia v databázových systémoch a na úrovni jazyka SQL? (Nápoveda: Indexy)
Zásobníkové automaty akceptujú istú triedu formálnych jazykov v Chomského hierarchii. Definujte zásobníkový automat. Uveďte príklad jazyka patriaceho do tejto triedy. Uveďte, ako by ste dokázali, že tento jazyk patrí do tejto triedy. Ako by ste zásobník implementovali vo vhodnom programovacom jazyku? Podporujú databázové systémy prácu so zásobníkmi? (Nápoveda: Štandardné relačné DBMS nemajú priamu podporu zásobníkov, ale LIFO správanie sa dá simulovať pomocou tabuliek a napr. časových značiek. )
Definujte strom ako štruktúru. V akých situáciách ste sa stretli s využitím stromových štruktúr (resp. s uložením údajov v strome)? (Nápoveda: B-stromy). Ako sa v týchto situáciách využívajú stromy? Existuje nejaká súvislosť medzi aritmetickými výrazmi a stromovými štruktúrami? Ako by ste vyjadrili gramatiku aritmetického výrazu?
...
Váš domáci labák z databázových systémov
Portál DBS_Lab je online prostredie, kde budete získavať a prezerať si svoje bodové hodnotenia z previerok a domácich úloh. Umožňuje Vám pracovať priamo s databázou a získavať okamžitú spätnú väzbu na Vaše riešenia.
Všetky výsledky Vašich previerok a odovzdaných úloh sú automaticky zaznamenávané a dostupné vo Vašom profile. Nezabudnite, že pravidelné odovzdávanie domácich úloh na portáli DBS_Lab je kľúčové pre úspešné absolvovanie predmetu.
Prejsť na portál DBS_LabV prípade problémov kontaktujte emailom cvičiaceho.
Vaša spätná väzba je pre nás dôležitá! Pomôžte nám zlepšiť výučbu.
Trvá to len pár minút a pomôže nám prispôsobiť výučbu Vašim potrebám.