Jednou jeden kolega na jedné své přednášce řekl, že nejhorším sloupcem v tabulkách je sloupec poznámka. Často se stává, že do poznámky se pak ukládají jinde neumístitelná data, protože s datovým modelem se různých důvodů nechce hýbat. Pak pro výběr dat z takovéhoto sloupce musíte používat složitou heuristiku.
Mohu to potvrdit z vlastní praxe. Normalizace datového modelu databáze pomůže těmto i mnohým jiným problémům lehce předcházet. Dnes bychom se podívali na to, jak by se s takovou poznámkou mělo zacházet. Neboli 1. normální forma. V tomto článku čerpám ze svých materiálů z přednášky „Entitno relační modelování“ (březen 2016).
Tabulka je v 1. NF právě když :
V Excelu jsme vytvořili seznam členů spolku a protože jich máme již hodně, rozhodneme se je převést do relační databáze. Tak vytvoříme kopií excelovského souboru v datbáze a dostaneme toto :
jmeno (text) |
adresa (text) |
---|---|
Michal Pohnoutka starší | Brno, Květná 25, Bohunice, 612 04 |
Linda Krásná | Litoval, náměstí míru, 487 00 |
Móric Beňovský gróf | Slovakia, Kláštor na riekou, 82, 945 32 |
Michal Pohnoutka mladší | Brno, Květná 25, Bohunice, 612 04 |
Krásná tabulka, která není v 1. normální formě. Ptáte se proč? Pojďme společně ověřit si data.
1. Každý sloupec má jedinečný název v rámci tabulky.
Splněno OK. Máme jméno a pak adresu
2. Každý sloupec má jeden datový typ.
Splněno OK
3. Žádné dva řádky nemohou obsahovat stejné hodnoty (primární klíč tabulky).
Splněno. Od katastorfy nás v případě Michala Pohnoutky zachránilo pouze to že za příjmení jsme dali přívlastek. Asi bychom mněli zavést něco jako osobní číslo, které by bylo pro každého člena jedinečné.
4. Každý sloupec musí obsahovat jednu hodnotu (atomičnost).
Splněno ? Ne určitě ne. Sloupec jméno obsahuje vlastní jméno, příjmení, titul- nebo přívlastek. Adresa taky obsahuje Stát, Město,ulici, číslo popisném, část obce a psč. Ptáme se jak bychom pomocí SQL jazyka např: vzbrali seznam všech měst. Asi těžko.
Proto bychom měli udělat následující úpravu uložení dat v tabulce.
osobni_cislo (integer) |
jmeno (text) |
prijemni (text) |
titul (text) |
mesto (text) |
ulice (text) |
cislo (text) |
cast_obce (text) |
psc (char(6)) |
stat (text) |
---|---|---|---|---|---|---|---|---|---|
1 | Michal | Pohnoutka | st. | Brno | Květná | 25 | Bohunice | 61204 | Česko |
2 | Linda | Krásná | Litovel | náměstí Míru | 12 | 48700 | Česko | ||
3 | Moric | Beňovský | gróf | Kláštor nad riekou | 82 | 94532 | Slovensko | ||
4 | Michal | Pohnoutka | ml. | Brno | Květná | 25 | Bohunice | 61204 | Česko |
Takhle jsem zabespečili, že jednak jsou data uložená v atomické podobě a jednak jsou jednoduše identifikovaná pomocí jedinečného klíče osobní číslo.
Mnozí z nás se naučili pracovat a myslet v intentcích tabulkových procesorů jako je Excel. První věcí když nepostačuje sílá Excelu, je uložit data do databáze. V PostgreSQL to jde velice jednoduše. Data uložíte do .cvs formátu (uložit jako) a buďto příkazy copy nebo /copy nebo přes fdw dostaneme data do databáze. Pak můžeme dostat tuhle tabulku.
kategorie | 1_mesic | hodnota | 2_mesic | hodnota2 | 3_mesic | hodnota3 | ||
---|---|---|---|---|---|---|---|---|
Kategorie A | 11.1.1998 | 12,3 | 14.2.1998 | 56,25 | 7.3.1998 | 2,3 | ||
20.1.1998 | 45 | 20.2.1998 | 12,8 | 15.3.1998 | 5,12 | |||
30.1.1998 | 0,5 | 24.2.1998 | 14,2 |
Pro jistotu jednotlivé sloupce jsou v datovém typu text.
Takáto tabulka v databáze není v 1. normální formě. Proč ?
1. Podmínka je splněna. Každý sloupec má jedinečný název. I kdybychom se pokusili vytvořit tabulku se stejným pojmenováním sloupců, tak PostgreSQL nám to neumožní.
2. Podmínka je splněna. Každý sloupec má jeden datový typ. V našem případě text, protože ten je univerzální. Zde bych se zastavil. Zvolili jsme datový typ text, ale sami vidíme, že některé sloupce jsou skutečně textové jako kategorie. Ale jiná jsou datumová např. 1_měsíc a jiná typu number. Tak to zase tak s 2. podmínkou není úplně v pořádku. Později si vysvětlíme proč.
3. Žádné dva řádky nemohou obsahovat stejné hodnoty. OK splněno i když tabulce je to v tomto případě jedno, ale nám by nemnělo. Výběr dat v relační datbáze je pomocí řádku a položme si otázku. Jak bychom zde vybrali 2. řádek pomocí SQL dotazu?
4. Každý sloupec musí obsahovat jednu hodnotu. OK splněno. Do opravdy ? Např 2. řádek tabulky je jaké kategorie ? Excelovské myšlení nám říká přece Kategorie A, ale relační databázové myšlení nám říká null. Kdybych vybrali data pomocí SQL příkazu, tak hodnota by byla null.
Řekneme si tak co, splněno. Ano máme pravdu splněno z pohledu syntaxe. Ale z pohledu sémantiku ne. Jak bychom například spočetli průměrnou hodnotu ? No museli bychom spočítat průměrnou hodnotu za jednotlivé měsíce a ty pak zprůměrovat. Zbytečně složité i když proveditelné. Jednoduše je to možné upravit datovou strutktúru tak, aby odpovídala sématice 1. NF.
Zkusme se ji zformulovat :
1. Každá tabulka musí obsahovat jedinečný primární klíč, pomocí kterého se dají identifikovat a měnit popisná data daného konkrétního řádku tabulky.
2. Každý řádek tabulky musí obsahovat izolovaná data tak, aby byla nezávislá oproti jiným řádkům tabulky.
3. Sloupce musí být redukovány tak, aby obsahovala sématicky (významově) stejná data aniž by se narušila jejich jedinečnost v rámci tabulky.
4. Každý sloupec musí obsahovat sémanticky jeden druh dat.
V praxi to znamená, že zavedeme primární klíč tabulky. V tomto případě abstraktní id.
Pak kategorii všude doplníme v každém řádku tabulky.
Sloučime sloupce 1_mesic,2_mesic,3_mesic do sloupce datum a hodnota, hodnota2, hodnota3 do sloupce hodnota. Zvětší se nám sice počet řádků, ale zmenší se šířka tabulky.
Výslední podoba tabulky bude :
id | kategorie | datum | hodnota |
---|---|---|---|
1 | Kategorie A | 11.1.1998 | 12,3 |
2 | Kategorie A | 20.1.1998 | 45 |
3 | Kategorie A | 30.1.1998 | 0,5 |
4 | Kategorie A | 14.2.1998 | 56,25 |
5 | Kategorie A | 20.2.1998 | 12,8 |
6 | Kategorie A | 24.2.1998 | 14,2 |
7 | Kategorie A | 7.3.1998 | 2,3 |
8 | Kategorie A | 15.3.1998 |
Nebo kdyby Jste si nepamatovali to hroznou sématickou definici, vzpomente si na tento příklad.
EAV tabulky (entita – atribut – hodnota) nejsou taky v 1. NF. Protože nesplňují 4. pravidlo , že jeden sloupec obsahuje jednu kategorii dat a syntaktické pravidlo,každý sloupec má jeden datový typ.
(V budoucnu přidám příklad)
Podle mně taky nejsou v 1.NF, protože nedodržují minimálně pravidlo atomičnosti. V PostgreSQL se to obchází pomocí funkcí, pomocí kterých je možné separovat data a vracet je do atomické podoby v 1.NF.
A co datový typ datum. Hm. Posudte samy … :)
Hnidopišská poznámka: sloupčky "titul" a "cislo" pořád nejsou atomické, protože mohou (a budou) obsahovat více údaje. U čísla je to jasné: jedná se o číslo popisné, nebo číslo orientační? Běžně tam budou lidi zadávat jedno nebo druhé, nebo oboje. Tady je to naprosto jasné, rozdělit na dva sloupečky.
V případě titulu je jediná plná normální forma vazební tabulka na tabulku titulů (m:n), a to možná dokonce dvě (jeden titul před jménem, jeden za jménem). Zda je to rozumné, to už nechávám na každém.
No a ještě k těm adresám - v závislosti na použití se ještě může stát že budou potřeba další sloupečky, např. pro číslo bytu, stát/region, PO box a tak dále a tak dále. No a nakonec tam stejně nakonec vznikne sloupeček pro poznámku, protože kam jinam dát informaci "mimo pracovní dobu zvoňte dvakrát"?
Ale jinak dobrý blogpost, jen tak dál.
SQL Developer
Přečteno 31 915×
Přečteno 19 529×
Přečteno 19 483×
Přečteno 17 225×
Přečteno 16 211×