Co je Chinook databáze?
Chinook je testovací databáze digitálního hudebního obchodu. Hodí se pro výuku SELECTu, JOINů, agregací, filtrování i práce s datem.
Hudební katalog
Tabulky Artist, Album, Track, Genre, MediaType, Playlist a PlaylistTrack.
Zákazníci
Tabulka Customer obsahuje zákazníky, kontakty, adresy, zemi a obchodního zástupce.
Faktury
Tabulky Invoice a InvoiceLine umožňují řešit tržby, počty prodejů a položky faktur.
Zaměstnanci
Tabulka Employee ukazuje zaměstnance, nadřízené a obchodní zástupce zákazníků.
Nejdůležitější vazby
Artist.ArtistId = Album.ArtistId
Album.AlbumId = Track.AlbumId
Track.GenreId = Genre.GenreId
Track.MediaTypeId = MediaType.MediaTypeId
Customer.CustomerId = Invoice.CustomerId
Invoice.InvoiceId = InvoiceLine.InvoiceId
Track.TrackId = InvoiceLine.TrackId
Employee.EmployeeId = Customer.SupportRepId
Employee.EmployeeId = Employee.ReportsTo
Playlist.PlaylistId = PlaylistTrack.PlaylistId
Track.TrackId = PlaylistTrack.TrackId
Nejčastější rozdíly syntaxe
Toto jsou rozdíly, které uživatelé nejčastěji potkají při přechodu mezi MSSQL, Oracle a MySQL/MariaDB.
| Situace | MSSQL | Oracle | MySQL/MariaDB |
|---|---|---|---|
| Prvních 10 řádků | SELECT TOP 10 |
FETCH FIRST 10 ROWS ONLY |
LIMIT 10 |
| Spojení textu | FirstName + ' ' + LastName |
FirstName || ' ' || LastName |
CONCAT(FirstName, ' ', LastName) |
| Aktuální datum | GETDATE() |
SYSDATE |
NOW() |
| Zaokrouhlení | ROUND(value, 2) |
ROUND(value, 2) |
ROUND(value, 2) |
| Alias sloupce | AS AliasName |
AS AliasName |
AS AliasName |
| Podmínka textu | LIKE '%Rock%' |
LIKE '%Rock%' |
LIKE '%Rock%' |
| Datum z faktury | YEAR(InvoiceDate) |
EXTRACT(YEAR FROM InvoiceDate) |
YEAR(InvoiceDate) |
SQL příklady nad Chinook
Každý blok obsahuje variantu pro MSSQL, Oracle a MySQL/MariaDB.
1. Prvních 10 skladeb
TrackId, Name pojmenovaný jako TrackName a UnitPrice. Zobraz prvních 10 řádků z tabulky Track.
MSSQL
TOPSELECT TOP 10
TrackId
,Name AS TrackName
,UnitPrice
FROM Track
ORDER BY Name;
Oracle
FETCHSELECT
TrackId
,Name AS TrackName
,UnitPrice
FROM Track
ORDER BY Name
FETCH FIRST 10 ROWS ONLY;
MySQL/MariaDB
LIMITSELECT
TrackId
,Name AS TrackName
,UnitPrice
FROM Track
ORDER BY Name
LIMIT 10;
2. Celé jméno zákazníka
CustomerId, celé jméno zákazníka pojmenované jako CustomerName a Country. Výsledek seřaď podle celého jména zákazníka.
MSSQL
+SELECT
CustomerId
,FirstName + ' ' + LastName AS CustomerName
,Country
FROM Customer
ORDER BY CustomerName;
Oracle
||SELECT
CustomerId
,FirstName || ' ' || LastName AS CustomerName
,Country
FROM Customer
ORDER BY CustomerName;
MySQL/MariaDB
CONCATSELECT
CustomerId
,CONCAT(FirstName, ' ', LastName) AS CustomerName
,Country
FROM Customer
ORDER BY CustomerName;
+, Oracle používá || a MySQL/MariaDB používá funkci CONCAT().
3. Skladby včetně alba, interpreta a žánru
TrackName, název alba jako AlbumTitle, název interpreta jako ArtistName a název žánru jako GenreName. Výsledek omez na 50 řádků a seřaď podle interpreta, alba a skladby.
MSSQL
JOINSELECT TOP 50
t.Name AS TrackName
,al.Title AS AlbumTitle
,ar.Name AS ArtistName
,g.Name AS GenreName
FROM Track t
INNER JOIN Album al ON t.AlbumId = al.AlbumId
INNER JOIN Artist ar ON al.ArtistId = ar.ArtistId
INNER JOIN Genre g ON t.GenreId = g.GenreId
ORDER BY
ar.Name
,al.Title
,t.Name;
Oracle
JOINSELECT
t.Name AS TrackName
,al.Title AS AlbumTitle
,ar.Name AS ArtistName
,g.Name AS GenreName
FROM Track t
INNER JOIN Album al ON t.AlbumId = al.AlbumId
INNER JOIN Artist ar ON al.ArtistId = ar.ArtistId
INNER JOIN Genre g ON t.GenreId = g.GenreId
ORDER BY
ar.Name
,al.Title
,t.Name
FETCH FIRST 50 ROWS ONLY;
MySQL/MariaDB
JOINSELECT
t.Name AS TrackName
,al.Title AS AlbumTitle
,ar.Name AS ArtistName
,g.Name AS GenreName
FROM Track t
INNER JOIN Album al ON t.AlbumId = al.AlbumId
INNER JOIN Artist ar ON al.ArtistId = ar.ArtistId
INNER JOIN Genre g ON t.GenreId = g.GenreId
ORDER BY
ar.Name
,al.Title
,t.Name
LIMIT 50;
4. Počet skladeb podle žánru
GenreName a počet skladeb v daném žánru jako TrackCount. Výsledek seřaď od největšího počtu skladeb.
MSSQL
GROUP BYSELECT
g.Name AS GenreName
,COUNT(t.TrackId) AS TrackCount
FROM Genre g
INNER JOIN Track t ON g.GenreId = t.GenreId
GROUP BY g.Name
ORDER BY TrackCount DESC;
Oracle
GROUP BYSELECT
g.Name AS GenreName
,COUNT(t.TrackId) AS TrackCount
FROM Genre g
INNER JOIN Track t ON g.GenreId = t.GenreId
GROUP BY g.Name
ORDER BY TrackCount DESC;
MySQL/MariaDB
GROUP BYSELECT
g.Name AS GenreName
,COUNT(t.TrackId) AS TrackCount
FROM Genre g
INNER JOIN Track t ON g.GenreId = t.GenreId
GROUP BY g.Name
ORDER BY TrackCount DESC;
GROUP BY je proto dobře přenositelná mezi databázemi.
5. Žánry s více než 100 skladbami
GenreName a počet skladeb jako TrackCount. Zobraz pouze žánry, které mají více než 100 skladeb.
MSSQL
HAVINGSELECT
g.Name AS GenreName
,COUNT(t.TrackId) AS TrackCount
FROM Genre g
INNER JOIN Track t ON g.GenreId = t.GenreId
GROUP BY g.Name
HAVING COUNT(t.TrackId) > 100
ORDER BY TrackCount DESC;
Oracle
HAVINGSELECT
g.Name AS GenreName
,COUNT(t.TrackId) AS TrackCount
FROM Genre g
INNER JOIN Track t ON g.GenreId = t.GenreId
GROUP BY g.Name
HAVING COUNT(t.TrackId) > 100
ORDER BY TrackCount DESC;
MySQL/MariaDB
HAVINGSELECT
g.Name AS GenreName
,COUNT(t.TrackId) AS TrackCount
FROM Genre g
INNER JOIN Track t ON g.GenreId = t.GenreId
GROUP BY g.Name
HAVING COUNT(t.TrackId) > 100
ORDER BY TrackCount DESC;
COUNT() nelze běžně filtrovat pomocí WHERE. Pro filtrování výsledků po seskupení slouží HAVING.
6. Tržby podle zákazníka
CustomerName, zemi zákazníka a celkové tržby jako TotalSales. Výsledek seřaď podle tržeb od nejvyšších.
MSSQL
+SELECT
c.FirstName + ' ' + c.LastName AS CustomerName
,c.Country
,SUM(i.Total) AS TotalSales
FROM Customer c
INNER JOIN Invoice i ON c.CustomerId = i.CustomerId
GROUP BY
c.FirstName
,c.LastName
,c.Country
ORDER BY TotalSales DESC;
Oracle
||SELECT
c.FirstName || ' ' || c.LastName AS CustomerName
,c.Country
,SUM(i.Total) AS TotalSales
FROM Customer c
INNER JOIN Invoice i ON c.CustomerId = i.CustomerId
GROUP BY
c.FirstName
,c.LastName
,c.Country
ORDER BY TotalSales DESC;
MySQL/MariaDB
CONCATSELECT
CONCAT(c.FirstName, ' ', c.LastName) AS CustomerName
,c.Country
,SUM(i.Total) AS TotalSales
FROM Customer c
INNER JOIN Invoice i ON c.CustomerId = i.CustomerId
GROUP BY
c.FirstName
,c.LastName
,c.Country
ORDER BY TotalSales DESC;
7. Tržby podle interpreta
ArtistName a celkové tržby za jeho skladby jako TotalSales. Výsledek seřaď podle tržeb od nejvyšších.
MSSQL
SUMSELECT
ar.Name AS ArtistName
,SUM(il.UnitPrice * il.Quantity) AS TotalSales
FROM InvoiceLine il
INNER JOIN Track t ON il.TrackId = t.TrackId
INNER JOIN Album al ON t.AlbumId = al.AlbumId
INNER JOIN Artist ar ON al.ArtistId = ar.ArtistId
GROUP BY ar.Name
ORDER BY TotalSales DESC;
Oracle
SUMSELECT
ar.Name AS ArtistName
,SUM(il.UnitPrice * il.Quantity) AS TotalSales
FROM InvoiceLine il
INNER JOIN Track t ON il.TrackId = t.TrackId
INNER JOIN Album al ON t.AlbumId = al.AlbumId
INNER JOIN Artist ar ON al.ArtistId = ar.ArtistId
GROUP BY ar.Name
ORDER BY TotalSales DESC;
MySQL/MariaDB
SUMSELECT
ar.Name AS ArtistName
,SUM(il.UnitPrice * il.Quantity) AS TotalSales
FROM InvoiceLine il
INNER JOIN Track t ON il.TrackId = t.TrackId
INNER JOIN Album al ON t.AlbumId = al.AlbumId
INNER JOIN Artist ar ON al.ArtistId = ar.ArtistId
GROUP BY ar.Name
ORDER BY TotalSales DESC;
InvoiceLine. Tabulka Invoice obsahuje souhrn za celou fakturu, která může mít více položek.
8. Tržby podle roku faktury
InvoiceYear a součet tržeb jako TotalSales. Výsledek seřaď podle roku.
MSSQL
YEAR()SELECT
YEAR(InvoiceDate) AS InvoiceYear
,SUM(Total) AS TotalSales
FROM Invoice
GROUP BY YEAR(InvoiceDate)
ORDER BY InvoiceYear;
Oracle
EXTRACTSELECT
EXTRACT(YEAR FROM InvoiceDate) AS InvoiceYear
,SUM(Total) AS TotalSales
FROM Invoice
GROUP BY EXTRACT(YEAR FROM InvoiceDate)
ORDER BY InvoiceYear;
MySQL/MariaDB
YEAR()SELECT
YEAR(InvoiceDate) AS InvoiceYear
,SUM(Total) AS TotalSales
FROM Invoice
GROUP BY YEAR(InvoiceDate)
ORDER BY InvoiceYear;
YEAR(), Oracle používá EXTRACT().
9. CASE výraz pro délku skladby
TrackName, její délku v milisekundách a nově vytvořenou kategorii délky jako TrackLengthCategory. Výsledek seřaď od nejdelších skladeb a zobraz pouze 30 řádků.
MSSQL
CASESELECT TOP 30
Name AS TrackName
,Milliseconds
,CASE
WHEN Milliseconds < 180000 THEN 'Krátká skladba'
WHEN Milliseconds BETWEEN 180000 AND 300000 THEN 'Běžná skladba'
ELSE 'Dlouhá skladba'
END AS TrackLengthCategory
FROM Track
ORDER BY Milliseconds DESC;
Oracle
CASESELECT
Name AS TrackName
,Milliseconds
,CASE
WHEN Milliseconds < 180000 THEN 'Krátká skladba'
WHEN Milliseconds BETWEEN 180000 AND 300000 THEN 'Běžná skladba'
ELSE 'Dlouhá skladba'
END AS TrackLengthCategory
FROM Track
ORDER BY Milliseconds DESC
FETCH FIRST 30 ROWS ONLY;
MySQL/MariaDB
CASESELECT
Name AS TrackName
,Milliseconds
,CASE
WHEN Milliseconds < 180000 THEN 'Krátká skladba'
WHEN Milliseconds BETWEEN 180000 AND 300000 THEN 'Běžná skladba'
ELSE 'Dlouhá skladba'
END AS TrackLengthCategory
FROM Track
ORDER BY Milliseconds DESC
LIMIT 30;
10. Zaměstnanec a jeho nadřízený
EmployeeName, jeho pracovní pozici jako EmployeeTitle a celé jméno jeho nadřízeného jako ManagerName. Použij propojení tabulky Employee sama na sebe.
MSSQL
Self JOINSELECT
e.FirstName + ' ' + e.LastName AS EmployeeName
,e.Title AS EmployeeTitle
,manager.FirstName + ' ' + manager.LastName AS ManagerName
FROM Employee e
LEFT JOIN Employee manager ON e.ReportsTo = manager.EmployeeId
ORDER BY EmployeeName;
Oracle
Self JOINSELECT
e.FirstName || ' ' || e.LastName AS EmployeeName
,e.Title AS EmployeeTitle
,manager.FirstName || ' ' || manager.LastName AS ManagerName
FROM Employee e
LEFT JOIN Employee manager ON e.ReportsTo = manager.EmployeeId
ORDER BY EmployeeName;
MySQL/MariaDB
Self JOINSELECT
CONCAT(e.FirstName, ' ', e.LastName) AS EmployeeName
,e.Title AS EmployeeTitle
,CONCAT(manager.FirstName, ' ', manager.LastName) AS ManagerName
FROM Employee e
LEFT JOIN Employee manager ON e.ReportsTo = manager.EmployeeId
ORDER BY EmployeeName;
11. INSERT, UPDATE, DELETE - testovací interpret
Artist, následně uprav jeho název a nakonec testovací záznam smaž.
MSSQL
DMLINSERT INTO Artist (
Name
)
VALUES (
'Test Artist'
);
UPDATE Artist
SET Name = 'Test Artist Updated'
WHERE Name = 'Test Artist';
DELETE FROM Artist
WHERE Name = 'Test Artist Updated';
Oracle
DMLINSERT INTO Artist (
Name
)
VALUES (
'Test Artist'
);
UPDATE Artist
SET Name = 'Test Artist Updated'
WHERE Name = 'Test Artist';
DELETE FROM Artist
WHERE Name = 'Test Artist Updated';
MySQL/MariaDB
DMLINSERT INTO Artist (
Name
)
VALUES (
'Test Artist'
);
UPDATE Artist
SET Name = 'Test Artist Updated'
WHERE Name = 'Test Artist';
DELETE FROM Artist
WHERE Name = 'Test Artist Updated';
INSERT, UPDATE a DELETE vyžadují práva pro zápis. Uživatelé s oprávněním pouze pro čtení obvykle pracují hlavně s příkazy typu SELECT.
Rychlý tahák pro výuku
Stručné shrnutí, co se mezi databázemi mění a co zůstává stejné.
Většinou stejné
SELECT,FROM,WHEREINNER JOIN,LEFT JOINGROUP BY,HAVINGORDER BYCOUNT(),SUM(),AVG(),MIN(),MAX()CASE WHEN ... THEN ... ELSE ... ENDINSERT,UPDATE,DELETEv základní podobě
Často rozdílné
- Omezení počtu řádků:
TOP,FETCH,LIMIT - Spojování textu:
+,||,CONCAT() - Datumové funkce:
GETDATE(),SYSDATE,NOW() - Získání roku z data:
YEAR()vs.EXTRACT() - Automatické číslování ID
- Procedury a funkce: T-SQL, PL/SQL, SQL/PSM nebo specifická syntaxe
Doporučený výklad pro studenty
| Téma | Jednoduché vysvětlení | Příklad nad Chinook |
|---|---|---|
| SELECT | Vyberou se konkrétní sloupce z tabulky. | Skladby z tabulky Track. |
| WHERE | Filtrují se řádky před seskupením. | Zákazníci z Czech Republic. |
| JOIN | Spojují se tabulky podle společného klíče. | Track → Album → Artist. |
| GROUP BY | Vytváří se souhrn podle vybraného sloupce. | Počet skladeb podle žánru. |
| HAVING | Filtrují se až hotové skupiny. | Jen žánry s více než 100 skladbami. |
| CASE | Vytváří se vlastní kategorie podle podmínky. | Krátká, běžná a dlouhá skladba. |
| Datum | Každá databáze může mít trochu jinou syntaxi. | Tržby podle roku faktury. |
| DML | Příkazy pro vložení, úpravu a smazání dat. | Testovací interpret v Artist. |