Vydělávej až 160.000 Kč měsíčně! Akreditované rekvalifikační kurzy s garancí práce od 0 Kč. 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í.

Lekce 10 - MS-SQL krok za krokem: Další dotazy a vazba M:N

V minulé lekci, MS-SQL krok za krokem: Dotazy přes více tabulek (JOIN), jsme se naučili JOINy, tedy dotazy nad více tabulkami.

V tomto duchu budeme dnes v MS-SQL tutoriálu pokračovat, založíme si ještě jednu tabulku s komentáři a poté si řekneme něco o vazbě M:N.

Tabulka komentáře

Pokračujme v našem redakčním systému a vytvořme si tabulku Komentare. Komentář se (podobně jako článek) váže na uživatele. Váže se ale také na článek. Máme zde tedy dvě vazby 1:N. Jeden článek má N komentářů, jeden uživatel má N komentářů. Komentář patří vždy pouze jednomu uživateli a jednomu článku.

Jelikož komentář je část a patří do dvou celků (k článku a k uživateli), bude obsahovat 2 sloupce s Id článku a Id komentáře. Těmto sloupcům s Id položky z cizí tabulky říkáme cizí klíče. Již je známe z minula (u článku byl cizí klíč uživatele), jen jsme si neřekli, že se jim tak říká. Kromě nich bude mít komentář text a datum.

CREATE TABLE [Komentare] (
    [Id] INT IDENTITY,
    [ClanekId] INT,
    [UzivatelId] INT,
    [Obsah] NVARCHAR(MAX),
    [Datum] DATETIME,
    PRIMARY KEY ([Id])
);

Vložme si nějaké komentáře:

INSERT INTO [Komentare] ([UzivatelId], [Obsah], [Datum], [ClanekId]) VALUES
(4, 'Super článek!', '2012-4-6', 1),
(4, 'Jak je tedy přesně ta podmínka pro vznik bakterie?', '2011-1-28', 2),
(1, 'Zasekla jsem se v této hře, kde najdu klíč do 3. levelu?', '2011-9-30', 3),
(4, 'Jak rozjedu plošinu v 5. levelu?', '2010-8-1', 3),
(1, 'Umřel jsem a nemám hru uloženou, co mám dělat?', '2012-4-14', 4),
(3, 'Dobrá hra!', '2012-4-6', 4),
(3, 'Nerozumím tomu!', '2011-4-6', 1),
(2, 'Super článek!', '2012-5-6', 1);

Pojďme si zkusit vypsat všechny komentáře spolu s jejich autory a články, ke kterým patří. JOINy již umíme, tento dotaz bude obdobný, jen bude rovnou přes 2 tabulky najednou, čili s dvěma JOINy. JOINů můžeme mít v dotazu samozřejmě kolik chceme, ale měli bychom pamatovat na to, že to nejsou pro databázi úplně jednoduché operace.

SELECT [Uzivatele].[Prezdivka], [Komentare].[Obsah], [Clanky].[Titulek]
FROM [Komentare]
INNER JOIN [Uzivatele] ON [Uzivatele].[Id] = [Komentare].[UzivatelId]
INNER JOIN [Clanky] ON [Clanky].[Id] = [Komentare].[ClanekId]
ORDER BY [Komentare].[Datum];

Výsledek:

Prezdivka Obsah Titulek
Ema Jak rozjedu plošinu v 5. levelu? Cheese Mouse
Ema Jak je tedy přesně ta podmínka... Bakterie
Denny Nerozumím tomu! Algoritmus
Míša Zasekla jsem se v této hře... Cheese Mouse
Ema Super článek! Algoritmus
Denny Dobrá hra! Pacman
Míša Umřel jsem a nemám hru uloženou... Pacman
David Super článek! Algoritmus

Všimněte si, že jsme všechny sloupce předsadili názvem tabulky. Mělo by se to tak dělat vždy. Zde konkrétně se jmenuje Obsah obsah komentáře i obsah článku. U složitější struktury databáze se toto stává se sloupci jako Datum, Id, Autor...

Zkuste si dotaz bez názvů tabulek, nebude fungovat.

-- tento dotaz nebude fungovat
SELECT [Uzivatele].[Prezdivka], [Komentare].[Obsah], [Clanky].[Titulek]
FROM [Komentare]
INNER JOIN [Uzivatele] ON [Id] = [UzivatelId]
INNER JOIN [Clanky] ON [Id] = [ClanekId]
ORDER BY [Komentare].[Datum];

MS-SQL vyhodí hlášku:

Msg 209, Level 16, State 1, Line 4
Ambiguous column name 'Id'.
Msg 209, Level 16, State 1, Line 5
Ambiguous column name 'Id'.

U složitějších dotazů přes více tabulek může být výhodné použít aliasy. Aliasy již také umíme, deklarují se přes klíčové slovo AS. Použijme je v tomto dotazu.

SELECT [U].[Prezdivka], [K].[Obsah], [C].[Titulek]
FROM [Komentare] AS [K]
INNER JOIN [Uzivatele] AS [U] ON [U].[Id] = [K].[UzivatelId]
INNER JOIN [Clanky] AS [C] ON [C].[Id] = [K].[ClanekId]
ORDER BY [K].[Datum];

Dotaz vypadá mnohem přehledněji, nemusíme opisovat názvy tabulek. Zkrátili jsme si je, zde jen na počáteční písmena.

Sekce

Pokračujme ve struktuře redakčního systému. Články se řadí do sekcí, ty jsou uloženy v tabulce Sekce. Je tu však malý háček. Jedna sekce může obsahovat několik článků. Jeden článek však může také patřit do několika sekcí.

Pro účely redakčního systému by samozřejmě stačilo, aby článek spadal vždy jen do jedné sekce. Tak bychom se ale nic nenaučili :)

Narážíme na vazbu M:N.

Vazba M:N

Vazbu M:N jsme si již vysvětlili, dalším příkladem by mohli být třeba student a předmět. Každý student chodí na několik předmětů a každý předmět má několik studentů, kteří na něj dochází.

Pojďme si založit tabulku sekcí. Bude velmi triviální, protože v ní budou jen 2 sloupce. Jeden s Id sekce a druhý s jejím názvem.

CREATE TABLE [Sekce] (
    [Id] INT IDENTITY,
    [Nazev] NVARCHAR(155),
    PRIMARY KEY ([Id])
);

Naplňme si ji daty:

INSERT INTO [Sekce] ([Nazev]) VALUES
('Algoritmy'),
('Hry');

Databáze jako taková vazbu M:N neumí. To pro nás ale není překážkou a běžně se to obchází vytvořením tzv. vazební tabulky. Vazební tabulka nenese sama o sobě žádná data a slouží pouze k propojení dvou tabulek. Každý řádek vazební tabulky bude obsahovat Id článku a Id sekce, tak je spolu propojí. Díky tomu můžeme dotazem zjistit jaké články jsou v sekci nebo do kterých sekcí článek patří. Založme si vazební tabulku, pojmenujeme ji ClanekSekce:

CREATE TABLE [ClanekSekce] (
    [Id] INT IDENTITY,
    [ClanekId] INT,
    [SekceId] INT,
    PRIMARY KEY ([Id])
);

Nyní ji naplníme daty, která nám články a sekce propojí:

INSERT INTO [ClanekSekce] ([ClanekId], [SekceId]) VALUES
(1, 1),
(2, 1),
(2, 2),
(3, 2),
(4, 2);

A zkusme si dotaz. Vypišme si články v sekci Algoritmy. Vybereme články, ty propojíme pomocí tabulky ClanekSekce se sekcí.

SELECT [C].[Url], [C].[Titulek]
FROM [Clanky] AS [C]
INNER JOIN [ClanekSekce] AS [CS] ON [CS].[ClanekId] = [C].[Id]
INNER JOIN [Sekce] AS [S] ON [CS].[SekceId] = [S].[Id]
WHERE [S].[Nazev] = 'Algoritmy';

Výsledek:

Url Titulek
co-je-to-algoritmus Algoritmus
bakterie-bunecny-automat Bakterie

Dotaz výše by byl na webu opravdu použit pro vypsání obsahu sekce. Podle vazební tabulky jsme propojili články se sekcí. Vlastně jsme připojili ty řádky vazební tabulky, které spojují daný článek a ten článek potom k jeho sekci.

To by dnes již stačilo. Ono by to vůbec na chvíli stačilo, již toho víme dost.

V následujícím cvičení, Řešené úlohy k 8.-10. lekci MS-SQL, si procvičíme nabyté zkušenosti z předchozích lekcí.


 

Předchozí článek
MS-SQL krok za krokem: Dotazy přes více tabulek (JOIN)
Všechny články v sekci
MS-SQL databáze krok za krokem
Přeskočit článek
(nedoporučujeme)
Řešené úlohy k 8.-10. lekci MS-SQL
Článek pro vás napsal Michal Žůrek - misaz
Avatar
Uživatelské hodnocení:
264 hlasů
Autor se věnuje tvorbě aplikací pro počítače, mobilní telefony, mikroprocesory a tvorbě webových stránek a webových aplikací. Nejraději programuje ve Visual Basicu a TypeScript. Ovládá HTML, CSS, JavaScript, TypeScript, C# a Visual Basic.
Aktivity