Zavolá se relace obsahující cizí klíč. Omezení primárního a cizího klíče. Obr.3.4. Normalizovaná množina vztahů

Poslední aktualizace: 07/02/2017

Databáze mohou obsahovat tabulky, které jsou vzájemně propojeny různými vazbami. Vztah představuje spojení mezi entitami různých typů.

Při výběru vztahu se vybere primární nebo nadřazená tabulka (tabulka primárních klíčů / hlavní tabulka) a závislá podřízená tabulka (tabulka cizích klíčů / podřízená tabulka). Podřízená tabulka závisí na nadřazené tabulce.

Cizí klíče se používají k organizaci komunikace. Cizí klíč představuje jeden nebo více sloupců z jedné tabulky, který je zároveň potenciálním klíčem z jiné tabulky. Cizí klíč se nemusí shodovat s primárním klíčem z hlavní tabulky. I když zpravidla cizí klíč ze závislé tabulky ukazuje na primární klíč z hlavní tabulky.

Vztahy mezi tabulkami jsou následujících typů:

    Jedna ku jedné

    Jeden k mnoha

    mnoho pro mnoho(Mnoho k mnoha)

Komunikace jedna ku jedné

Tento typ připojení se často nenachází. V tomto případě může být objekt jedné entity spojen pouze s jedním objektem jiné entity. Například na některých webech může mít uživatel pouze jeden blog. To znamená, že vzniká vztah: jeden uživatel – jeden blog.

Tento typ vztahu často zahrnuje rozdělení jednoho velkého stolu na několik malých. Primární nadřazená tabulka v tomto případě nadále obsahuje často používaná data, zatímco podřízená tabulka obvykle ukládá data, ke kterým se přistupuje méně často.

V tomto ohledu je primární klíč závislé tabulky zároveň cizím klíčem, který odkazuje na primární klíč hlavní tabulky.

Například tabulka Uživatelé představuje uživatele a má následující sloupce:

    UserId(id, primární klíč)

    Jméno (uživatelské jméno)

A tabulka Blogy představuje uživatelské blogy a má následující sloupce:

    BlogId (identifikátor, primární a cizí klíč)

    Jméno (název blogu)

V tomto případě bude sloupec BlogId ukládat hodnotu ze sloupce UserId z tabulky uživatelů. To znamená, že sloupec BlogId bude fungovat jako primární i cizí klíč.

Vztah jeden k mnoha

Toto je nejběžnější typ připojení. V tomto typu vztahu závisí více řádků z podřízené tabulky na jednom řádku v nadřazené tabulce. Jeden blog může mít například několik článků. V tomto případě je tabulka blogů nadřazená a tabulka článků podřízená. Tedy jeden blog – mnoho článků. Nebo jiný příklad, několik fotbalistů může hrát ve fotbalovém týmu. A přitom jeden fotbalista může hrát vždy jen v jednom týmu. Tedy jeden tým – mnoho hráčů.

Mějme například tabulku nazvanou Články, která představuje články blogu a má následující sloupce:

    ArticleId(id, primární klíč)

    BlogId (cizí klíč)

    Název (název článku)

    Text (text článku)

V tomto případě bude sloupec BlogId z tabulky článků ukládat hodnotu ze sloupce BlogId z tabulky blogů.

vztah mnoho k mnoha

S tímto typem vztahu může být jeden řádek z tabulky A spojen s mnoha řádky z tabulky B. Jeden řádek z tabulky B může být naopak spojen s mnoha řádky z tabulky A. Typickým příkladem jsou studenti a kurzy: jeden student může absolvovat několik kurzů, a proto se do jednoho kurzu může zapsat několik studentů.

Dalším příkladem jsou články a značky: pro jeden článek lze definovat několik značek a pro několik článků lze definovat jednu značku.

Ale v SQL Server na úrovni databáze nemůžeme vytvořit přímý vztah many-to-many mezi dvěma tabulkami. To se provádí pomocí pomocné pracovní tabulky. Někdy data z této pracovní tabulky představují samostatnou entitu.

Například v případě článků a tagů nechť existuje tabulka Tagy, která má dva sloupce:

    TagId(identifikátor, primární klíč)

    Text (text značky)

Nechte také existovat mezitabulku ArticleTags s následujícími poli:

    TagId (identifikátor, primární a cizí klíč)

    ArticleIdId (identifikátor, primární a cizí klíč)

Technicky získáme dva vztahy one-to-many. Sloupec TagId z tabulky ArticleTags bude odkazovat na sloupec TagId z tabulky Tags. A sloupec ArticleId z tabulky ArticleTags bude odkazovat na sloupec ArticleId z tabulky Articles. To znamená, že sloupce TagId a ArticleId v tabulce ArticleTags představují složený primární klíč a jsou také cizími klíči pro vztah s tabulkami Articles a Tags.

Integrita referenčních dat

Při změně primárního a cizího klíče je třeba dodržet následující aspekt: integrita referenčních dat(referenční integrita). Jeho základní myšlenkou jsou dvě tabulky v databázi, které uchovávají stejná data, aby byla zachována konzistence. Integrita dat představuje správně vytvořené vztahy mezi tabulkami se správnými vazbami mezi nimi. V jakých případech může být narušena integrita dat:

    Anomálie mazání(anomálie mazání). Vyvolá se, když je z hlavní tabulky odstraněn řádek. V tomto případě cizí klíč ze závislé tabulky nadále odkazuje na odstraněný řádek z hlavní tabulky

    Anomálie vkládání(anomálie vkládání). Nastane, když je řádek vložen do závislé tabulky. V tomto případě se cizí klíč ze závislé tabulky neshoduje s primárním klíčem žádného z řádků z hlavní tabulky.

    Aktualizujte anomálie(aktualizace anomálie). S takovou anomálií může několik řádků stejné tabulky obsahovat data, která patří stejnému objektu. Když změníte data v jednom řádku, může dojít ke konfliktu s daty v jiném řádku.

Anomálie mazání

Chcete-li vyřešit anomálii odstranění, musíte nastavit jedno ze dvou omezení na cizí klíč:

    Pokud řádek ze závislé tabulky nutně vyžaduje řádek z hlavní tabulky, pak se pro cizí klíč nastaví kaskádové odstranění. To znamená, že když je odstraněn řádek z hlavní tabulky, související řádky jsou odstraněny ze závislé tabulky.

    Pokud řádek ze závislé tabulky neumožňuje žádný vztah s řádkem z hlavní tabulky (to znamená, že takový vztah je volitelný), je cizí klíč nastaven na hodnotu NULL, když je související řádek odstraněn z hlavní tabulky. V tomto případě musí mít sloupec cizího klíče hodnotu null.

Anomálie vkládání

Chcete-li vyřešit anomálii vložení při přidávání dat do závislé tabulky, musí mít sloupec, který představuje cizí klíč, hodnotu null. Pokud tedy přidaný objekt nemá žádné spojení s hlavní tabulkou, sloupec cizího klíče bude obsahovat hodnotu NULL.

Aktualizujte anomálie

K vyřešení problému anomálie aktualizace se používá normalizace, o které bude řeč později.

Poslední aktualizace: 27.04.2019

Cizí klíče umožňují vytvořit vztahy mezi tabulkami. Cizí klíč je nastaven na sloupce ze závislé, podřízené tabulky a ukazuje na jeden ze sloupců z hlavní tabulky. Cizí klíč obvykle ukazuje na primární klíč ze související hlavní tabulky.

Obecná syntaxe pro nastavení cizího klíče na úrovni tabulky je:

CIZÍ KLÍČ (sloupec1, sloupec2, ... sloupecN) REFERENCE main_table (main_table_column1, main_table_column2, ... main_table_columnN)

Chcete-li vytvořit omezení cizího klíče, za FOREIGN KEY zadáte sloupec tabulky, který bude reprezentovat cizí klíč. A za klíčovým slovem REFERENCES je uveden název související tabulky a v závorce pak název souvisejícího sloupce, na který bude cizí klíč ukazovat. Za výrazem REFERENCES následují výrazy ON DELETE a ON UPDATE, které určují akci při mazání a aktualizaci řádku z hlavní tabulky.

Definujme například dvě tabulky a propojme je pomocí cizího klíče:

CREATE TABLE Customers (Id INT PRIMARY KEY AUTO_INCREMENT, Age INT, FirstName VARCHAR(20) NOT NULL, LastName VARCHAR(20) NOT NULL, Phone VARCHAR(20) NOT NULL UNIQUE); CREATE TABLE Orders (Id INT PRIMARY KEY AUTO_INCREMENT, CustomerId INT, CreatedAt Date, FOREIGN KEY (CustomerId) REFERENCE Customers (Id));

V tomto případě jsou definovány tabulky Zákazníci a Objednávky. Zákazníci jsou hlavní a zastupují klienta. Objednávky jsou závislé a představují objednávku zadanou zákazníkem. Tabulka Objednávky je propojena prostřednictvím sloupce CustomerId s tabulkou Customers a jejím sloupcem ID. To znamená, že sloupec CustomerId je cizí klíč, který odkazuje na sloupec ID z tabulky Customers.

Operátor CONSTRAINT můžete použít k zadání názvu pro omezení cizího klíče:

CREATE TABLE Objednávky (Id INT PRIMARY KEY AUTO_INCREMENT, CustomerId INT, CreatedAt Date, CONSTRAINT orders_custonmers_fk CIZÍ KLÍČ (CustomerId) REFERENCE Zákazníci (Id));

PŘI VYMAZÁNÍ a PŘI AKTUALIZACI

Pomocí příkazů ON DELETE a ON UPDATE můžete nastavit akce, které se provedou při odstranění nebo změně souvisejícího řádku z hlavní tabulky. Jako akci lze použít následující možnosti:

    CASCADE: Automaticky odstraní nebo upraví řádky ze závislé tabulky, když jsou odstraněny nebo změněny související řádky v hlavní tabulce.

    SET NULL: Při odstraňování nebo aktualizaci souvisejícího řádku z hlavní tabulky nastaví sloupec cizího klíče na hodnotu NULL. (V tomto případě musí sloupec cizího klíče podporovat nastavení NULL)

    OMEZIT: Odmítne odstranění nebo úpravu řádků v hlavní tabulce, pokud v závislé tabulce existují související řádky.

    ŽÁDNÁ AKCE: stejná jako OMEZIT.

    SET DEFAULT: Při odstraňování souvisejícího řádku z hlavní tabulky nastaví sloupec cizího klíče na výchozí hodnotu, která je určena pomocí atributu DEFAULT. Navzdory skutečnosti, že tato možnost je v zásadě dostupná, engine InnoDB tento výraz nepodporuje.

Kaskádové mazání

Kaskádové odstranění vám umožňuje automaticky odstranit všechny související řádky ze závislé tabulky, když odstraníte řádek z hlavní tabulky. Chcete-li to provést, použijte možnost CASCADE:

CREATE TABLE Objednávky (Id INT PRIMÁRNÍ KLÍČ AUTO_INCREMENT, CustomerId INT, CreatedAt Date, CIZÍ KLÍČ (CustomerId) REFERENCE Zákazníci (ID) NA DELETE CASCADE);

Výraz ON UPDATE CASCADE funguje podobným způsobem. Když změníte hodnotu primárního klíče, automaticky se změní hodnota jeho přidruženého cizího klíče. Protože se však primární klíče mění velmi zřídka a obecně se nedoporučuje používat jako primární klíče sloupce s měnitelnými hodnotami, výraz ON UPDATE se v praxi používá jen zřídka.

Nastavení NULL

Když nastavíte možnost SET NULL pro cizí klíč, sloupec cizího klíče musí mít hodnotu NULL:

CREATE TABLE Objednávky (Id INT PRIMARY KEY AUTO_INCREMENT, CustomerId INT, CreatedAt Date, FOREIGN KEY (CustomerId) REFERENCE Customers (Id) ON DELETE SET NULL);

Obrázek ukazuje tabulku (poměr stupně 5) obsahující některé informace o zaměstnancích hypotetického podniku. Řádky tabulky odpovídají n-ticím. Každý řádek je vlastně popisem jednoho reálného objektu (v tomto případě zaměstnance), jehož charakteristiky jsou obsaženy ve sloupcích. Relační vztahy odpovídají množinám entit a n-tice odpovídají entitám. Volají se sloupce v tabulce představující relační vztah atributy.

Každý atribut je definován na doméně, takže doménu lze považovat za sadu platných hodnot pro daný atribut. Ve stejné doméně lze definovat více atributů stejného vztahu a dokonce i atributy různých vztahů.

Je volán atribut, jehož hodnota jednoznačně identifikuje n-tice klíč (nebo jednoduše klíč). Klíčem je atribut Personnel Number, protože jeho hodnota je pro každého zaměstnance podniku jedinečná. Pokud jsou n-tice identifikovány pouze zřetězením hodnot několika atributů, pak se říká, že vztah má složený klíč.

Primární klíč- v relačním datovém modelu jeden z potenciálních klíčů vztahu, vybraný jako primární klíč (nebo výchozí klíč).

Vztah může obsahovat více klíčů. Jeden z klíčů je vždy deklarován hlavní, jeho hodnoty nelze aktualizovat. Všechny ostatní relační klíče jsou volány možné klíče.

Z teoretického hlediska jsou všechny potenciální (možné) relační klíče ekvivalentní, to znamená, že mají stejné vlastnosti jedinečnosti a minimalizace. Primární klíč se však obvykle vybírá z potenciálních klíčů, který je nejvhodnější pro určité praktické účely, například pro vytváření externí klíče v jiných ohledech nebo vytvořit seskupený index. Proto se jako primární klíč zpravidla volí ten, který má nejmenší velikost (fyzické úložiště) a/nebo obsahuje nejmenší počet atributů.

Li primární klíč sestává z jediného atributu, tzv s jednoduchým klíčem.

Li primární klíč sestává ze dvou nebo více atributů, tzv složený klíč. Takže jméno, příjmení, patronymie, číslo pasu, série pasů nemohou být primárními klíči jednotlivě, protože mohou být stejné pro dvě nebo více osob. Neexistují však dva osobní doklady stejného typu se stejnou sérií a číslem. Proto v relaci obsahující data o osobách může být primárním klíčem podmnožina atributů sestávající z typu osobního dokladu, jeho řady a čísla.



Na rozdíl od hierarchických a síťových datových modelů nemá relační model koncept skupinového vztahu. K vyjádření asociací mezi n-ticemi různých vztahů se používá duplikace jejich klíčů.

Volají se atributy, které jsou kopiemi klíčů jiných vztahů cizí klíče.

Například vztah mezi vztahy ODDĚLENÍ a ZAMĚSTNANEC se vytvoří zkopírováním primárního klíče "Číslo_oddělení" z prvního vztahu do druhého. Pro získání seznamu zaměstnanců daného oddělení je tedy nutné: ​​1) Z tabulky ODDĚLENÍ nastavit hodnotu atributu "Číslo_oddělení" , odpovídající tomuto „Název_oddělení“. 2) vyberte všechny záznamy z tabulky ZAMĚSTNANEC, hodnota atributu "Číslo_oddělení" což je stejné jako v předchozím kroku. Abyste zjistili, ve kterém oddělení zaměstnanec pracuje, musíte provést obrácenou operaci: 1) Určete "Číslo_oddělení" z tabulky ZAMĚSTNANCE. 2) Pomocí získané hodnoty najdeme záznam v tabulce ODDĚLENÍ.


18. Normalizace v relačních databázích, koncept normální formy v návrhu databáze.

Normální forma - vlastnost vztahu v relačním datovém modelu, charakterizující jej z hlediska redundance, která může potenciálně vést k logicky chybným výsledkům vzorkování nebo změny dat. Normální forma je definována jako soubor požadavků, které musí vztah splňovat.

Proces převodu databáze do normální formy se nazývá normalizace . Normalizace má přinést strukturu databáze do podoby, která poskytuje minimální redundanci, to znamená, že normalizace nemá za cíl snížit nebo zvýšit produktivitu práce nebo snížit nebo zvýšit objem databáze. Konečným cílem normalizace je snížit potenciální nekonzistenci informací uložených v databázi.



Odstranění redundance se provádí zpravidla rozkladem vztahů tak, že v každé relaci jsou uložena pouze primární fakta (tedy skutečnosti, které nejsou odvozeny z jiných uložených skutečností).

Funkční závislosti.

Relační databáze obsahuje jak strukturální, tak sémantické informace. Struktura databáze je určena počtem a typem vztahů, které obsahuje, a vztahy jedna k mnoha, které existují mezi n-ticemi těchto vztahů. Sémantická část popisuje množinu funkčních závislostí, které existují mezi atributy těchto vztahů. Definujme funkční závislost.

19. 1NF: Základní definice a transformační pravidla.

K diskusi o první normální formě jsou nutné dvě definice:

Jednoduchý atribut - atribut, jehož hodnoty jsou atomické (nedělitelné).

Komplexní atribut - získává se spojením několika atomických atributů, které lze definovat na stejných nebo různých doménách (nazývá se také vektorový nebo datový agregát).

Definice první normální formy:

vztah je v 1NF, pokud jsou hodnoty všech jeho atributů atomické. . Jinak to vůbec není tabulka a takové atributy je třeba rozložit.

Podívejme se na příklad:

V databázi personálního oddělení podniku je nutné uchovávat informace o zaměstnancích, které se lze pokusit prezentovat ve vztahu k

ZAMĚSTNANEC(ČÍSLO_ZAMĚSTNANCE, JMÉNO, DATUM NAROZENÍ, PRACOVNÍ_HISTORIE, DĚTI).

Z pečlivého zvážení tohoto vztahu vyplývá, že atributy "pracovní historie" A "děti" jsou složité, navíc atribut "pracovní historie" obsahuje další komplexní atribut "historie platů".
Tyto jednotky vypadají takto:

 JOB_HISTORY (RECEPTION_DATE, NAME, SALARY_HISTORY),

 SALARY_HISTORY (APPOINTMENT_DATE, SALARY),

 CHILDREN (CHILD_NAME, BIRTH_YEAR).

Jejich zapojení je na Obr. 3.3.

Obr.3.3. Počáteční postoj.

Aby se původní vztah SLUŽBA dostal do první normální formy, je nutné jej rozložit na čtyři vztahy, jak je znázorněno na následujícím obrázku:

Obr.3.4. Normalizovaná množina vztahů.

Zde je primární klíč každého vztahu zvýrazněn modrým rámečkem, názvy cizích klíčů jsou modrým písmem. Připomeňme, že cizí klíče se používají k reprezentaci funkčních závislostí, které existují ve zdrojovém vztahu. Tyto funkční závislosti jsou označeny čarami se šipkami.

Normalizační algoritmus popsal E.F. Codd takto:

  • Počínaje relací v horní části stromu (obrázek 3.3.) se vezme její primární klíč a každá bezprostředně podřízená relace se rozšíří vložením domény nebo kombinace domén tohoto primárního klíče.
  • Primární klíč každého takto rozšířeného vztahu se skládá z Primárního klíče, který měl vztah před rozšířením, a přidaného Primárního klíče nadřazeného vztahu.
  • Poté jsou z rodičovského vztahu odstraněny všechny nejednoduché domény, je odstraněn horní uzel stromu a stejný postup se opakuje pro každý ze zbývajících podstromů.

20. 2NF: Základní definice a transformační pravidla.

Primární klíč vztahu velmi často obsahuje několik atributů (v takovém případě se nazývá kompozitní) - viz např. vztah DĚTI znázorněný na Obr. 3.4 otázka 19. Současně je představen pojem plná funkční závislost.

Definice:

neklíčový atribut je funkčně plně závislý na složeném klíči, pokud je funkčně závislý na celém klíči jako celku, ale není funkčně závislý na žádném z jeho základních atributů.

Příklad:

Nechť existuje vztah NABÍDKA (N_DODAVATEL, PRODUKT, CENA).
Dodavatel může dodávat různé produkty a stejný produkt mohou dodávat různí dodavatelé. Pak je klíč vztahu "N_dodavatel + produkt". Ať všichni dodavatelé dodávají zboží za stejnou cenu. Pak máme následující funkční závislosti:

  • N_dodavatel, produkt -> cena
  • produkt -> cena

Neúplná funkční závislost atributu price (cena) na klíči vede k následující anomálii: když se změní cena položky, je vyžadován úplný pohled na vztah, aby se změnily všechny záznamy o jejích dodavatelích. Tato anomálie je důsledkem toho, že v jedné datové struktuře jsou spojeny dvě sémantické skutečnosti. Následující rozšíření dává vztahy v 2NF:

  • DORUČENÍ (N_SUPPLIER, PRODUKT)
  • PRODUCT_PRICE (PRODUCT, PRICE)

Takže můžete dát

Definice druhé normální formy: Relace je v 2NF, pokud je v 1NF a každý neklíčový atribut je plně funkčně závislý na klíči.

21. 3NF: Základní definice a transformační pravidla.

Než se budeme zabývat třetí normální formou, je nutné představit koncept: tranzitivní funkční závislost.

Definice:

Nechť X, Y, Z jsou tři atributy nějaké relace. V tomto případě X --> Y a Y --> Z, ale nedochází k obrácené korespondenci, tzn. Z -/-> Y a Y -/-> X. Potom Z závisí tranzitivně na X.
Nechť existuje vztah STORAGE ( FIRMA, SKLAD, OBJEM), který obsahuje informace o firmách přijímajících zboží ze skladů a objemy těchto skladů. Klíčový atribut - "firma". Pokud může každá společnost přijímat zboží pouze z jednoho skladu, pak v tomto ohledu existují následující funkční závislosti:

  • firma -> skladem
  • skladem -> hlasitost

V tomto případě vznikají anomálie:

  • pokud v tuto chvíli žádná firma nepřijímá zboží ze skladu, nelze údaje o jeho objemu vložit do databáze (protože není definován atribut key)
  • pokud se změní objem skladu, je nutné zobrazit celý vztah a změnit karty u všech firem spojených s tímto skladem.

K odstranění těchto anomálií je nutné rozložit původní vztah na dva:

  • ÚLOŽNÝ PROSTOR ( FIRMA, SKLADEM)
  • STORAGE_VOLUME ( SKLADEM, HLASITOST)

Definice třetí normální formy:

Relace je v 3NF, pokud je v 2NF a každý neklíčový atribut není přechodně závislý na primárním klíči.

InterBase může používat následující typy omezení:
  • PRIMÁRNÍ KLÍČ - primární klíč tabulky.
  • UNIQUE - jedinečný klíč tabulky.
  • CIZÍ KLÍČ- cizí klíč, poskytuje odkaz na jinou tabulku a zaručuje referenční integritu mezi nadřazeným a dětské stoly.

Poznámka k terminologii

Pokud jste jako autor tohoto kurzu v tom, že rádi hledáte odpovědi na otázku, která vás zajímá komplexně, v různých dílech různých autorů, pak jste si nemohli nevšimnout určitého zmatku v definicích hlavní (master) -> podřízený (detail) tabulky. Připomeňme, že hlavní tabulka se často nazývá nadřazená tabulka a podřízená tabulka se často nazývá podřízená tabulka.

To je pravděpodobně způsobeno tím, jak jsou tyto definice interpretovány v lokálních a SQL serverových DBMS.

V lokálních DBMS je hlavní tabulka ta, která obsahuje hlavní data, a podřízená tabulka obsahuje další data. Vezměme si například tři související tabulky. První obsahuje údaje o prodejích, druhý o produktech a třetí o zákaznících:


Rýže. 18.1.

Zde jsou hlavní informace uloženy v prodejní tabulce, jedná se tedy o hlavní (nadřazenou) tabulku. Další informace jsou uloženy v tabulkách produktů a zákazníků, což znamená, že jde o děti. Je to pochopitelné: jedna dcera nemůže mít dvě biologické matky, ale jedna matka je docela schopná porodit dvě dcery.

Ale v SQL databázových serverech existuje jiná definice vztahů: když jedno pole v tabulce odkazuje na pole v jiné tabulce, je to tzv. cizí klíč. A pole, na které odkazuje, se nazývá rodič popř primární klíč. Tabulka, která má cizí klíč (odkaz na záznam v jiné tabulce), se často nazývá potomek a tabulka s rodičovský klíč- rodičovský. Také v definici vztahů říkají, že rodič může mít pouze jeden jedinečný záznam, na který může odkazovat několik záznamů dětský stůl.

Takže ve výše uvedeném příkladu má prodejní tabulka dva cizí klíče: ID produktu a ID zákazníka. A obě tabulky na pravé straně obrázku mají rodičovský klíč"Identifikátor". Protože se v prodejní tabulce může opakovaně objevit stejný zákazník nebo produkt, ukázalo se, že obě tabulky na pravé straně obrázku jsou rodiče a tabulka vlevo je dítě. Protože teď studujeme InterBase - SQL databázový server, těmito definicemi se budeme řídit v následujících přednáškách. Abychom si tímto zmatkem ještě nelámali hlavu, shodněme se hned: dětský stůl má cizí klíč (FOREIGN KEY) do jiné tabulky.

PRIMÁRNÍ KLÍČ

PRIMÁRNÍ KLÍČ- primární klíč je jedním z hlavních typů omezení v databázi. Primární klíč je navržen tak, aby jednoznačně identifikoval záznam v tabulce a musí být jedinečný. Primární klíče PRIMARY KEY se nacházejí v tabulkách, které se obvykle nazývají nadřazené (Parent). Primární klíč by neměl být zaměňován s primárními indexy lokálních databází, primární klíč není index, ale omezení. Při vytváření primárního klíče InterBase automaticky vytvoří pro něj jedinečný index. Pokud však tvoříme jedinečný index, toto se nevytvoří omezení primárního klíče. Tabulka může mít pouze jeden primární klíč, PRIMARY KEY.

Řekněme, že máte tabulku se seznamem zaměstnanců. Pole Příjmení může obsahovat duplicitní hodnoty (jmenovky), takže jej nelze použít jako primární klíč. Je to vzácné, ale jsou jmenovci, kteří se navíc jmenují stejně. Ještě vzácněji existují plnohodnotní jmenovci, takže ani všechna tři pole „Příjmení“ + „Jméno“ + „Patronymika“ nemohou zaručit jedinečnost záznamu a nemohou být primárním klíčem. V tomto případě je řešením, stejně jako dříve, přidat pole identifikátoru, které obsahuje sériové číslo této osoby. Taková pole se obvykle automaticky zvyšují (o organizaci automaticky se zvyšujících polí si povíme v příštích přednáškách). Tak,

Primární klíč je jedno nebo více polí v tabulce, jejichž kombinace je pro každý záznam jedinečná.

Pokud primární klíč obsahuje jeden sloupec (jak je tomu nejčastěji), použije se specifikátor PRIMARY KEY, když definice sloupce:

CREATE TABLE Prim_1(Stolbec1 INT NOT NULL PRIMÁRNÍ KLÍČ, Stolbec2 VARCHAR(50))

Pokud je primární klíč postaven na několika sloupcích, pak se specifikátor umístí po definování všech polí:

CREATE TABLE Prim_2(Stolbec1 INT NENÍ NULL, Stolbec2 VARCHAR(50) NOT NULL, PRIMÁRNÍ KLÍČ (Stolbec1, Stolbec2))

Jak je vidět z příkladů, primární klíč musí mít omezení sloupců NOT NULL.

UNIKÁTNÍ

UNIKÁTNÍ- jedinečný klíč. Specifikátor UNIQUE označuje, že všechny hodnoty tohoto pole musí být jedinečné, proto tato pole také nemohou obsahovat hodnoty NULA. Dalo by se říci, že UNIQUE klíč je alternativou k primárnímu klíči, ale existují rozdíly. Hlavní rozdíl je v tom, že musí existovat pouze jeden primární klíč, zatímco jedinečných klíčů může být několik. Navíc omezení UNIQUE nelze sestavit na stejné sadě sloupců, která byla použita pro PRIMARY KEY nebo jiné omezení UNIQUE. Jedinečné klíče, stejně jako primární klíče, se nacházejí v tabulkách, které jsou rodiči jiných tabulek.

Sloupec deklarovaný s omezením UNIQUE, jako je primární klíč, lze použít k vynucení referenční integrity mezi jeho nadřazeným a dětské stoly. V tomto případě cizí klíč dětský stůl bude odkazovat na tato pole. Stejně jako u primárního klíče, když je vytvořen jedinečný klíč, a jedinečný index. Ale ne naopak. Příklad vytvoření tabulky s jedním primárním a dvěma jedinečnými klíči:

CREATE TABLE Prim_3(Stolbec1 INT NOT NULL PRIMAR KEY, Stolbec2 VARCHAR(50) NOT NULL UNIQUE, Stolbec3 FLOAT NOT NULL UNIQUE)

CIZÍ KLÍČ

CIZÍ KLÍČ- externí klíč. Jedná se o velmi výkonný nástroj pro zajištění referenční integrity mezi tabulkami, který umožňuje nejen sledovat přítomnost správných odkazů, ale také je automaticky spravovat. Cizí klíče jsou obsaženy v tabulkách, které jsou potomky (Child) jiných tabulek. Referenční integrita je zajištěna právě cizím klíčem, který odkazuje na primární resp

A tak jsme potichu přistoupili k velmi důležitému tématu – primárnímu a cizímu klíči. Pokud to první používá téměř každý, pak to druhé nějak ignoruje. Ale marně. Cizí klíče nejsou problém, jsou skutečným pomocníkem v integritě dat.

1.2.5. Primární klíč

O klíčových polích jsme již mluvili hodně, ale nikdy jsme je nepoužili. Nejzajímavější je, že všechno fungovalo. To je výhoda nebo možná nevýhoda databází Microsoft SQL Server a MS Access. Tento trik nebude fungovat v tabulkách Paradox a bez pole klíče bude tabulka pouze pro čtení.

Do určité míry jsou klíče omezení a lze je zvážit ve spojení s příkazem CHECK, protože deklarace probíhá podobným způsobem a dokonce používá příkaz CONSTRAINT. Podívejme se na tento proces na příkladu. K tomu vytvoříme tabulku dvou polí „guid“ a „vcName“. Toto nastaví pole „guid“ jako primární klíč:

CREATE TABLE Globally_Unique_Data (jedinečný identifikátor guid DEFAULT NEWID(), vcName varchar(50), CONSTRAINT PK_guid PRIMARY KEY (Guid))

Nejlepší část je zde řada CONSTRAINT. Jak víme, za tímto klíčovým slovem následuje název omezení a deklarace klíče není výjimkou. Pro pojmenování primárního klíče doporučuji použít název jako PK_name, kde name je název pole, které by se mělo stát primárním klíčem. Zkratka PK pochází z primárního klíče.

Po tomto je místo klíčového slova CHECK, které jsme použili v omezeních, operátor PRIMARY KEY To znamená, že nepotřebujeme kontrolu, ale primární klíč. Jedno nebo více polí, která budou tvořit klíč, jsou uvedena v závorkách.

Pamatujte, že žádné dva řádky nemohou mít stejnou hodnotu v poli klíče, ve kterém je omezení primárního klíče totožné s omezením jedinečným. To znamená, že pokud z pole pro uložení příjmení uděláte primární klíč, pak nebude možné do takové tabulky zapsat dva Ivanovy s různými jmény. To porušuje omezení primárního klíče. To je důvod, proč jsou klíče omezení a jsou deklarovány stejným způsobem jako omezení CHECK. To ale neplatí pouze pro primární klíče a sekundární klíče s jedinečností.

V tomto příkladu je primárním klíčem pole typu uniqueidentifier (GUID). Výchozí hodnota pro toto pole je výsledkem procedury serveru NEWID.

Pozornost

Pro tabulku lze vytvořit pouze jeden primární klíč

Pro zjednodušení příkladů je vhodné použít jako klíč číselný typ a pokud to databáze umožňuje, bude lepší, když bude typu „autoincrement“ (automaticky rostoucí/snižující číslo). V MS SQL Server je toto pole IDENTITA a v MS Access je to pole typu „počítadlo“.

Následující příklad ukazuje, jak vytvořit tabulku produktů s automaticky se zvyšujícím celočíselným polem jako primárním klíčem:

CREATE TABLE Products (id int IDENTITY(1, 1), product varchar(50), Price money, Quantity numeric(10, 2), CONSTRAINT PK_id PRIMARY KEY (id))

Právě tento typ klíče budeme používat nejčastěji, protože pole klíče bude ukládat čísla, která jsou snadno srozumitelná a bude se s nimi snadněji a vizuálněji pracovat.

Primární klíč se může skládat z více než jednoho sloupce. Následující příklad vytvoří tabulku, ve které pole „id“ a „Produkt“ tvoří primární klíč, což znamená, že pro obě pole bude vytvořen jedinečný index:

CREATE TABLE Products1 (id int IDENTITY(1, 1), Product varchar(50), Price money, Quantity numeric (10, 2), CONSTRAINT PK_id PRIMARY KEY (id, [Product name])))

Programátoři velmi často vytvářejí databázi s klíčovým polem ve tvaru celého čísla, ale zároveň úkol jasně říká, že určitá pole musí být jedinečná. Proč rovnou nevytvořit primární klíč z těchto polí, která musí být jedinečná a nebude potřeba vytvářet samostatná řešení tohoto problému.

Jedinou nevýhodou vícesloupcového primárního klíče je problém s vytvářením vztahů. Zde se z toho musíte dostat pomocí různých metod, ale problém lze stále vyřešit. Stačí zadat pole typu uniqueidentifier a pomocí něj vytvořit připojení. Ano, v tomto případě získáme jedinečný primární klíč a pole typu uniqueidentifier, ale tato redundance v důsledku nebude větší než stejná tabulka, kde je primárním klíčem jedinečný identifikátor a na pole je nastaveno omezení jedinečnosti, které musí buď jedinečný. Co si vybrat? Záleží na konkrétním úkolu a na tom, s čím se vám lépe pracuje.

1.2.6. Externí klíč

Cizí klíč je také omezením CONSTRAINT a představuje vztah mezi dvěma tabulkami. Řekněme, že máte dvě tabulky:

  • Jména – obsahuje jména osob a skládá se z polí identifikátoru (pole klíče), jména.
  • Telefony je telefonní tabulka, která se skládá z identifikátoru (pole klíče), cizího klíče pro připojení k tabulce jmen a pole řetězce pro uložení telefonního čísla.

Jedna osoba může mít více telefonů, proto jsme datové úložiště rozdělili do různých tabulek. Obrázek 1.4 vizuálně ukazuje vztah mezi dvěma tabulkami. Pokud jste již pracovali s propojenými tabulkami, bude vám to stačit. Pokud o připojení slyšíte poprvé, zkusme se na problém podívat blíže.

Vezměme si například stůl tří lidí. Tabulka 1.3 ukazuje obsah tabulky "Jména". Existují pouze tři řádky a každý má svůj jedinečný hlavní klíč. Pro jedinečnost, když vytváříme tabulku, uděláme z klíče automaticky rostoucí pole.

Tabulka 1.3 Obsah tabulky Jména

Tabulka 1.4. Obsah tabulky Telefony

Tabulka 1.4 obsahuje pět telefonních čísel. Pole hlavního klíče také obsahuje jedinečný hlavní klíč, který lze také automaticky zvýšit. Sekundární klíč je vztah k primárnímu klíči tabulky Names. Jak toto spojení funguje? Petrov má jako primární klíč v tabulce Jména číslo 1 V tabulce Telefony v sekundárním klíči hledáme číslo 1 a získáme Petrova telefonní čísla. Totéž platí pro zbytek položek. Vizuálně je spojení vidět na obrázku 1.5.

Tento typ ukládání dat je velmi pohodlný. Pokud by nebylo možné vytvořit související tabulky, pak bychom v tabulce Jména museli zadat všechna telefonní čísla do jednoho pole. To je nepohodlné z hlediska použití, údržby a získávání dat.

V tabulce můžete vytvořit několik polí jmen, ale vyvstává otázka - kolik. Jeden člověk může mít jen 1 telefon, ale já mám třeba 3, nepočítám pracovní. Velké množství polí vede k redundanci dat.

V tabulce Jména můžete pro každý telefon vytvořit samostatný řádek s příjmením, ale to je snadné pouze pro takový jednoduchý příklad, kdy stačí zadat příjmení a můžete snadno provést několik záznamů pro Petrov s několika telefony čísla. Co když je 10 nebo 20 polí? Takže vytvoření dvou tabulek propojených cizím klíčem je vidět ve výpisu 1.6.

Výpis 1.6. Vytváření tabulek propojených cizím klíčem

CREATE TABLE Jména (idName int IDENTITY(1,1), vcName varchar(50), CONSTRAINT PK_guid PRIMARY KEY (idName),) CREATE TABLE Phones (idPhone int IDENTITY(1,1), idName int, vcPhone varchar(10), OMEZENÍ PK_idPhone PRIMÁRNÍ KLÍČ (idPhone), CONSTRAINT FK_idName CIZÍ KLÍČ (idName) REFERENCE Jména (idName))

Pečlivě si prostudujte obsah nabídky. Je to docela zajímavé, protože používá některé z operátorů, které jsme již probrali, a další příklad by byl užitečný. Pro obě tabulky je vytvořeno klíčové pole, které je na prvním místě, je typu int a je automaticky inkrementováno od 1 v krocích po jedné. Pole klíče se stane hlavním klíčem pomocí omezení CONSTRAINT.

V popisu tabulky Telefony je na posledním řádku pro nás nová deklarace, a to deklarace cizího klíče pomocí operátoru FOREIGN KEY. Jak vidíte, je to také omezení a o něco později uvidíte proč. Pole tabulky, které by mělo být propojeno s jinou tabulkou, je uvedeno v závorkách. Poté následuje klíčové slovo REFERENCES (link), název tabulky, se kterou má být spojení (Names) a v závorce název pole ("idName"). Tím jsme vytvořili spojení, které je znázorněno na obrázku 1.4.

Pozornost!

Cizí klíč může odkazovat pouze na primární klíč jiné tabulky nebo na jedinečné omezení. To znamená, že za klíčovým slovem REFERENCES musí být název tabulky a v závorkách lze zadat pouze primární klíč nebo pole s omezením UNIQUE. Jiná pole nelze zadat.

Nyní, pokud můžete vyplnit tabulky daty. Další tři týmy přidají tři jména, která jsme viděli v tabulce 1.3:

INSERT INTO Names(vcName) VALUES("Petrov") INSERT INTO Names(vcName) VALUES("Ivanov") INSERT INTO Names(vcName) VALUES("Sidorov")

Pokud jste již pracovali s SQL, můžete přidat položky pro telefonní tabulku. Tyto příkazy vynechám, ale můžete je vidět v souboru Foreign_keys.sql v adresáři Chapter1 na CD.

Naším úkolem je nyní zjistit, jaké jsou restriktivní akce cizího klíče, pojďme na to přijít. Zadali jsme explicitní vztah mezi dvěma poli v různých tabulkách. Pokud se pokusíte přidat do telefonní tabulky záznam s identifikátorem v poli "idName", který neexistuje ve stejnojmenném poli (jméno lze změnit na jiné) v tabulce s příjmeními, dojde k chybě. . Tím se přeruší vztah mezi dvěma tabulkami a omezení cizího klíče neumožní existenci záznamů bez vztahu.

Omezení platí i při změně nebo mazání záznamů. Pokud se například pokusíte odstranit řádek s příjmením Petrov, dojde k chybě omezení cizího klíče. Nemůžete odstranit záznamy, které mají externě související řádky. Nejprve je potřeba smazat všechna telefonní čísla k tomuto záznamu a teprve poté bude možné smazat řádek s příjmením Petrov.

Při vytváření cizího klíče můžete zadat ON DELETE CASCADE nebo ON UPDATE CASCADE. Pokud v tomto případě odstraníte Petrovův záznam z tabulky Jména nebo změníte identifikátor, budou všechny záznamy v tabulce Telefony spojené s Petrovovým řádkem automaticky aktualizovány. Nikdy. Ne, je třeba psát velkými písmeny: NIKDY to nedělejte. Vše je nutné ručně smazat nebo změnit. Pokud uživatel omylem smaže položku z tabulky Jména, odstraní se i odpovídající telefony. Nemá smysl vytvářet cizí klíč, pokud polovina jeho omezení zmizí! Vše musí být provedeno ručně a nikdy se nedoporučuje měnit identifikátory.

Mazání samotných tabulek by mělo také začínat podřízenou tabulkou, tedy Telefony, a teprve poté můžete odstranit hlavní tabulku Jména.

Nakonec vám ukážu, jak krásně získat shodu mezi jmény a telefonními čísly ze dvou tabulek:

SELECT vcName, vcPhone FROM Jména, Telefony WHERE Names.idName=Phones.idName

O takových dotazech si povíme podrobněji v kapitole 2. Prozatím jsem uvedl příklad jen proto, abyste viděli sílu souvisejících tabulek.

Tabulka může obsahovat až 253 cizích klíčů, což je docela dost i pro ty nejsložitější databáze. Osobně jsem musel pracovat s databázemi, kde počet cizích klíčů nepřesáhl 7 na tabulku. Pokud je to více, pak je s největší pravděpodobností databáze navržena nesprávně, i když existují výjimky.

Samotná tabulka může mít také maximálně 253 cizích klíčů. Cizí klíče v tabulce jsou méně obvyklé, obvykle ne více než 3. Nejčastěji může mít tabulka mnoho odkazů na jiné tabulky.

Cizí klíč může odkazovat na stejnou tabulku, ve které je vytvořen. Máte například tabulku pracovních názvů v organizaci, jak je uvedeno v tabulce 1.5. Tabulka se skládá ze tří polí: primární klíč, cizí klíč a pracovní pozice. Každá organizace může mít mnoho pozic, ale bylo by zcela logické zobrazit jejich jména a strukturu podřízenosti v jedné tabulce. K tomu musí být cizí klíč přidružen k primárnímu klíči tabulky pozic.

Tabulka 1.5. Tabulka s interním odkazem

Ve výsledku dostaneme, že generální ředitel má nulový cizí klíč, tzn. tato pozice stojí v čele všech ostatních. Pro obchodního ředitele a generálního ředitele ukazuje cizí klíč na řadu generálního ředitele. To znamená, že tyto dvě pozice podléhají přímo generálnímu řediteli. A tak dále.

Podívejme se, jak to vše můžeme vytvořit jako SQL dotaz:

CREATE TABLE Positions (idPosition int IDENTITY(1,1), idParentPosition int, vcName varchar(30), CONSTRAINT PK_idPosition PRIMÁRNÍ KLÍČ (idPosition), CONSTRAINT FK_idParentPosition CIZÍ KLÍČ (idParentPosition) REFERENCEs Positions)

Jak vidíte, cizí klíč jednoduše odkazuje na stejnou tabulku, kterou vytváříme. Na CD v adresáři Chapter1 vidíte v souboru Foreign_keys_to_self.sql příklad vytvoření této tabulky, její naplnění daty a zobrazení pozic s přihlédnutím k jejich podřízenosti. V další kapitole se podíváme na možnost práce s takovými tabulkami podrobněji.

Vztah jeden k jednomu

Zatím jsme se dívali na klasický vztah, kdy jeden řádek hlavní datové tabulky odpovídá jednomu řádku ze související tabulky. Tento vztah se nazývá one-to-many. Existují ale i další souvislosti a nyní se podíváme na další – jedna ku jedné, kdy je jeden záznam v hlavní tabulce spojen s jedním záznamem druhého. K realizaci stačí propojit primární klíče obou tabulek. Protože primární klíče nelze opakovat, v obou tabulkách může souviset pouze jeden řádek.

Následující příklad vytvoří dvě tabulky, které mají vztah primárního klíče:

CREATE TABLE Jména (idName uniqueidentifier DEFAULT NEWID(), vcName varchar(50), CONSTRAINT PK_guid PRIMÁRNÍ KLÍČ (idName)) CREATE TABLE Phones (idPhone uniqueidentifier DEFAULT NEWID(), vcPhone varchar(10), CONSTRAINT (CONSTRAINT PRIidMARYidPneKEY) OMEZENÍ FK_idPhone CIZÍ KLÍČ (idPhone) REFERENCE Jména (idName))

Pouze jedna z tabulek potřebuje cizí klíč. Vzhledem k tomu, že vztah je jedna ku jedné, nezáleží na tom, ve které tabulce jej vytvoříte.

mnoho pro mnoho

Nejsložitější vztah je mnoho k mnoha, kde mnoho záznamů z jedné tabulky odpovídá mnoha záznamům z jiné tabulky. K implementaci nestačí dvě tabulky.

Nejprve musíme pochopit, kdy lze použít vztah mnoho k mnoha? Řekněme, že máte dvě tabulky: seznam obyvatel domu a seznam telefonních čísel. Jeden byt může mít více čísel, to znamená, že jedno příjmení může mít dvě telefonní čísla. Ukazuje se, že existuje vztah jeden k mnoha. Na druhou stranu v jednom bytě mohou být dvě rodiny (společný byt nebo jen nájemník, který používá telefon majitele), což znamená, že spojení mezi telefonem a obyvatelem je také jedno až mnoho. A nejobtížnější možností je mít dva telefony ve společném bytě. V tomto případě obě čísla používá několik obyvatel bytu. Ukazuje se tedy, že „mnoho“ rodin může používat „mnoho“ telefonů (komunikace mnoho s mnoha).

Jak realizovat vztah mnoho k mnoha? V relačním modelu je to na první pohled nemožné. Asi před 10 lety jsem dlouho hledal různé možnosti a ve výsledku jsem jednoduše vytvořil jednu tabulku, která byla plná nadbytečných dat. Jednoho dne jsem ale dostal jeden úkol, díky kterému z podmínek vzešlo výborné řešení - potřeboval jsem vytvořit dvě tabulky obyvatel bytu a telefonních čísel a implementovat do nich pouze primární klíč. Cizí klíče nejsou v této tabulce potřeba. Ale spojení mezi stoly by mělo být přes třetí, spojovací stůl. Na první pohled je to obtížné a nejasné, ale jakmile tuto metodu pochopíte, uvidíte plnou sílu tohoto řešení.

V tabulkách 1.6 a 1.7 jsou uvedeny příklady tabulek příjmení a telefonních čísel. Tabulka 1.8 ukazuje tabulku propojení.

Tabulka 1.6. Tabulka příjmení

Tabulka 1.7. Telefonní stolek

Tabulka 1.8. Telefonní stolek

Podívejme se nyní, jaká bude logika vyhledávání dat ve vztahu many-to-many. Řekněme, že potřebujeme najít všechny telefony, které patří Ivanovovi. Ivanovův primární klíč je roven 1. V propojovací tabulce najdeme všechny záznamy, u kterých je pole „Vztah se jménem“ rovno 1. Půjde o záznamy 1 a 2. V těchto záznamech v poli „Vztah s telefonem“ jsou identifikátory 1 a 2, a To znamená, že Ivanov vlastní čísla z telefonního stolu, která se nacházejí v řádcích 1 a 2.

Nyní vyřešíme inverzní problém - určete, kdo má přístup k telefonnímu číslu 567575677. Toto číslo v telefonní tabulce má klíč 3. Hledáme všechny záznamy v propojovací tabulce, kde v poli “Telefonní připojení” je rovno 3. Jedná se o záznamy s čísly 4 a 5, které v poli "Name Link" obsahují hodnoty 2 a 3. Když se nyní podíváte na tabulku příjmení, uvidíte Petrova a Sidorova na číslech 2 a 3. To znamená, že tito dva obyvatelé používají telefonní číslo 567575677.

Prohlédněte si všechny tři tabulky a ujistěte se, že rozumíte tomu, která telefonní čísla patří kterým obyvatelům a naopak. Pokud toto spojení uvidíte, pochopíte, že je to jednoduché jako tři haléře a můžete to rychle implementovat do svých projektů.

CREATE TABLE Jména (idName uniqueidentifier DEFAULT NEWID(), vcName varchar(50), CONSTRAINT PK_guid PRIMÁRNÍ KLÍČ (idName)) CREATE TABLE Phones (idPhone uniqueidentifier DEFAULT NEWID(), vcPhone varchar(10), CONSTRAINT)ne PRIMÁRY_idPne CREATE TABLE LinkTable (idLinkTable uniqueidentifier DEFAULT NEWID(), idName uniqueidentifier, idPhone uniqueidentifier, CONSTRAINT PK_idLinkTable PRIMÁRNÍ KLÍČ (idLinkTable), CONSTRAINT FK_idPhone CIZÍ KLÍČ (idPhone) Nazev REFERENCE Telefony (idPhone FOREIGN s (idName ))

Propojovací tabulka má dva cizí klíče, které odkazují na jména a telefonní tabulky, a jeden primární klíč, který zajišťuje, že záznamy jsou jedinečné.

Pole GUID jsem zvolil jako primární klíč, protože je pro řešení tohoto konkrétního problému pohodlnější. Faktem je, že potřebujeme vložit záznamy do dvou tabulek a v obou případech musíme zadat stejný klíč. Hodnotu GUID lze vygenerovat a následně použít při vkládání dat do obou tabulek.

Jako klíč můžete také použít automaticky se zvětšující pole, ale v tomto případě je problém trochu obtížnější vyřešit, nebo spíše je nepohodlné problém vyřešit. Například při přidávání telefonního čísla musíte nejprve vložit odpovídající řádek do tabulky, pak jej najít, určit klíč, který byl danému řádku přiřazen, a poté provést spojení.

V této fázi se omezujeme pouze na vytváření tabulek, ale v sekci 2.8 se k tomuto tématu vrátíme a naučíme se pracovat se souvisejícími tabulkami. Práce se vztahem jedna k jedné a jedna k mnoha se příliš neliší, protože do tohoto schématu jsou zapojeny pouze dvě tabulky. Vztahy many-to-many jsou trochu komplikovanější kvůli propojovací tabulce, takže se tím budeme zabývat samostatně v části 2.27.




Horní