Pobieranie prezentacji. Proszę czekać

Pobieranie prezentacji. Proszę czekać

Bazy Danych W04: JOIN (złączenia) Wojciech St. Mościbrodzki

Podobne prezentacje


Prezentacja na temat: "Bazy Danych W04: JOIN (złączenia) Wojciech St. Mościbrodzki"— Zapis prezentacji:

1 Bazy Danych W04: JOIN (złączenia) Wojciech St. Mościbrodzki

2 JOIN – w pytaniach i odpowiedziach  Do czego służą operacje typu JOIN  Do umożliwienia wykonywania operacji (np. SELECT) na danych przechowywanych w wielu tabelach  Na jakich obiektach przeprowadza się JOIN  Operacje JOIN są wykonywane na dwóch (lub więcej) tablicach (zwykle – pozostających w pewnej relacji)  Jak wykonywane są "długie" operacje JOIN  Każdą wielotablicową operację JOIN można rozpatrywać jako łańcuch "binarnych" (dwutablicowych) JOINów.

3 Dane przykładowe do operacji JOIN  Rozpatrzmy dwa zbiory danych: encje STUDENT i JĘZYK create table pracownik ( id int auto_increment primary key, imie char(10), nazwisko char(30), placa int ); create table jezyk ( id int auto_increment primary key, nazwa char(15) ); insert into pracownik values (1,'Jan','Nowak',3400); insert into pracownik values (2,'Ewa','Malina',2100); insert into pracownik values (3,'Iza','Trus',4000); insert into jezyk values (11,'polski'); insert into jezyk values (12,'angielski'); insert into jezyk values (13,'niemiecki'); (w tej chwili nie ma pomiędzy naszymi encjami relacji)

4 Iloczyn kartezjański  Iloczyn kartezjański  Wersja algebry relacji: Iloczynem kartezjańskim zbiorów A i B nazywamy zbiór wszystkich par (a,b), takich, że a  A b  B  Wersja bazodanowa: iloczyn kartezjański dwóch encji A i B to zbiór wszystkich par (a,b), takich, że a jest elementem encji A, zaś b jest elementem encji B  Iloczyn kartezjański zawiera KAŻDĄ możliwą parę (zbiór wszystkich par) mysql> select * from pracownik, jezyk; | id | imie | nazwisko | placa | id | nazwa | | 1 | Jan | Nowak | 3400 | 11 | polski | | 2 | Ewa | Malina | 2100 | 11 | polski | | 3 | Iza | Trus | 4000 | 11 | polski | | 1 | Jan | Nowak | 3400 | 12 | angielski | | 2 | Ewa | Malina | 2100 | 12 | angielski | | 3 | Iza | Trus | 4000 | 12 | angielski | | 1 | Jan | Nowak | 3400 | 13 | niemiecki | | 2 | Ewa | Malina | 2100 | 13 | niemiecki | | 3 | Iza | Trus | 4000 | 13 | niemiecki |

5 Iloczyn kartezjański a relacja  Relację tworzą tylko te pary, które mają określoną właściwość (spełniają określony warunek).  Innymi słowy: relacja to jeden z podzbiorów iloczynu kartezjańskiego  Istnieje DUŻO możliwych relacji na dwóch encjach Relacja A (1-do-1): jaki język obowiązuje w kraju zamieszkania pracownika Relacja B (1-do-  ): jakie są języki ojczyste pracowników Relacja D (  -do-  ): jakimi językami mówią pracownicy Relacja C (1-do-1): jakiego języka uczą się pracownicy

6 Relacje zaimplementowane w bazie danych  Implementacja relacji wymaga dodania kolumny ( zakładamy relację 1-do-  ) alter table pracownik add column id_jez int;  Oczywiście istnieje wiele możliwych relacji 1-do-  na tych encjach: Relacja A (1-do-  ): jakie są języki ojczyste pracowników Relacja B (1-do-  ): główny język projektów naszych pracowników

7 Wykorzystanie operatora JOIN  Operatory JOIN (binarne, czyli na dwóch encjach) dzielimy na:  operatory INNER JOIN (odnoszą się tylko do elementów będących w relacji): EQUI JOIN (klasyczny INNER, wymaga równości pomiędzy kolumnami) NATURAL JOIN (wymaga równości, budowany w oparciu o nazwy kolumn)  operatory OUTER JOIN (dopuszczają elementy niebędące w relacji) LEFT OUTER (wszystkie elementy z encji po lewej stronie operatora) RIGHT OUTER (wszystkie elementy z encji po prawej stronie operatora) FULL OUTER (złożenie LEFT i RIGHT) NATURAL OUTER JOIN (OUTER budowany w oparciu o nazwy kolumn)  operator THETA JOIN (opiera się na warunku innym niż równość; rzadki)  operator ANTI JOIN (opiera się na warunku różności; rzadki)  operator CROSS JOIN (pełny iloczyn kartezjański)  Operator JOIN może występować także w wersji unarnej:  Operator SELF JOIN (tabela joinowana sama z sobą; raczej rzadki) Najważniejszą rolę pełnią INNER JOIN oraz OUTER JOIN (LEFT i RIGHT)

8 Dane do analizy  Wprowadzamy dane relacji update pracownik set id_jez=11 where id=1; update pracownik set id_jez=11 where id=2; update pracownik set id_jez=12 where id=3; Relacja (1-do-  ): główny język projektów naszych pracowników mysql> select * from pracownik; | id | imie | nazwisko | placa | id_jez | | 1 | Jan | Nowak | 3400 | 11 | | 2 | Ewa | Malina | 2100 | 11 | | 3 | Iza | Trus | 4000 | 12 | rows in set (0.00 sec) mysql> select * from jezyk; | id | nazwa | | 11 | polski | | 12 | angielski | | 13 | niemiecki | rows in set (0.01 sec)

9 INNER JOIN  INNER JOIN:  wymaga klauzuli ON (opisującej kolumny używane w warunku złączenia)  warunek zawsze zbudowany jest na równości (stąd nazwa: EQUI JOIN)  zwraca tylko te pary, które należą do relacji (WAŻNE!) mysql> SELECT * from pracownik INNER JOIN jezyk ON (pracownik.id_jez=jezyk.id);  równość id_jez=id występuje tylko 3 przypadkach  operator INNER JOIN zwraca podzbiór iloczynu kartezjańskiego  element, który nie znajduje się w relacji (nie wychodzi z niego żaden łuk) NIE ZOSTANIE zawarty w wyniku INNER JOIN | id | imie | nazwisko | placa | id_jez | id | nazwa | | 1 | Jan | Nowak | 3400 | 11 | 11 | polski | | 2 | Ewa | Malina | 2100 | 11 | 11 | polski | | 3 | Iza | Trus | 4000 | 12 | 12 | angielski |

10 OUTER JOIN  OUTER JOIN:  wymaga klauzuli ON (opisującej kolumny używane w warunku złączenia)  warunek równość LUB brak elementu po "drugiej" stronie  zwraca te pary, które należą do relacji ORAZ pary (element encji-NULL)(WAŻNE!) SELECT * from jezyk LEFT OUTER JOIN pracownik ON (jezyk.id=pracownik.id_jez);  warunek ( id=id_jez) lub (jezyk.id nie jest elementem relacji) występuje w 4 przypadkach  operator OUTER JOIN zwraca podzbiór ilocz. kart. ORAZ pary zbudowane "sztucznie" z elementu NULL  element, który nie znajduje się w relacji (nie wychodzi z niego żaden łuk) ZOSTANIE zawarty w wyniku OUTER JOIN (jeśli jest po "odpowiedniej stronie") | id | nazwa | id | imie | nazwisko | placa | id_jez | | 11 | polski | 1 | Jan | Nowak | 3400 | 11 | | 11 | polski | 2 | Ewa | Malina | 2100 | 11 | | 12 | angielski | 3 | Iza | Trus | 4000 | 12 | | 13 | niemiecki | NULL | NULL | NULL | NULL | NULL |

11 LEFT vs RIGHT OUTER JOIN Autorzy są "twórcami" książek KSIĄŻKAAUTOR | id | tytul | id_aut | id | nazwisko | | 1 | LOTR | 11 | 11 | Tolkien | | 2 | Hobbit | 11 | 11 | Tolkien | | 3 | Eden | 12 | 12 | Lem | | 4 | Dziady | NULL | NULL | NULL | | id | tytul | id_aut | id | nazwisko | | 1 | LOTR | 11 | 11 | Tolkien | | 2 | Hobbit | 11 | 11 | Tolkien | | 3 | Eden | 12 | 12 | Lem | | NULL | NULL | NULL | 13 | Reymont | select * from ksiazka RIGHT OUTER JOIN autor on (ksiazka.id_aut=autor.id); select * from ksiazka LEFT OUTER JOIN autor on (ksiazka.id_aut=autor.id); KSIĄŻKAAUTOR KSIĄŻKAAUTOR LEFT OUTER JOIN RIGHT OUTER JOIN NULL

12 LEFT, RIGHT i FULL OUTER JOIN | id | tytul | id_aut | id | nazwisko | | 1 | LOTR | 11 | 11 | Tolkien | | 2 | Hobbit | 11 | 11 | Tolkien | | 3 | Eden | 12 | 12 | Lem | | 4 | Dziady | NULL | NULL | NULL | |NULL| NULL | NULL | 13 | Reymont | | id | tytul | id_aut | id | nazwisko | | 1 | LOTR | 11 | 11 | Tolkien | | 2 | Hobbit | 11 | 11 | Tolkien | | 3 | Eden | 12 | 12 | Lem | | NULL | NULL | NULL | 13 | Reymont | select * from ksiazka RIGHT OUTER JOIN autor on (ksiazka.id_aut=autor.id); select * from ksiazka FULL OUTER JOIN autor on (ksiazka.id_aut=autor.id); LEFT OUTER NULL | id | tytul | id_aut | id | nazwisko | | 1 | LOTR | 11 | 11 | Tolkien | | 2 | Hobbit | 11 | 11 | Tolkien | | 3 | Eden | 12 | 12 | Lem | | 4 | Dziady | NULL | NULL | NULL | select * from ksiazka LEFT OUTER JOIN autor on (ksiazka.id_aut=autor.id); RIGHT OUTERFULL OUTER NULL

13 OUTER JOIN vs INNER JOIN | id | tytul | id_aut | id | nazwisko | | 1 | LOTR | 11 | 11 | Tolkien | | 2 | Hobbit | 11 | 11 | Tolkien | | 3 | Eden | 12 | 12 | Lem | | 4 | Dziady | NULL | NULL | NULL | |NULL| NULL | NULL | 13 | Reymont | | id | tytul | id_aut | id | nazwisko | | 1 | LOTR | 11 | 11 | Tolkien | | 2 | Hobbit | 11 | 11 | Tolkien | | 3 | Eden | 12 | 12 | Lem | | NULL | NULL | NULL | 13 | Reymont | LEFT OUTER NULL | id | tytul | id_aut | id | nazwisko | | 1 | LOTR | 11 | 11 | Tolkien | | 2 | Hobbit | 11 | 11 | Tolkien | | 3 | Eden | 12 | 12 | Lem | | 4 | Dziady | NULL | NULL | NULL | RIGHT OUTERFULL OUTER NULL | id | tytul | id_aut | id | nazwisko | | 1 | LOTR | 11 | 11 | Tolkien | | 2 | Hobbit | 11 | 11 | Tolkien | | 3 | Eden | 12 | 12 | Lem | INNER JOIN INNER JOIN LEFT OUTER RIGHT OUTER FULL OUTER

14 NATURAL JOIN  NATURAL JOIN jest przykładem JOINA, w którym:  warunek ON nie jest podawany w zapytaniu,  jest automatycznie generowany na podstawie NAZW kolumn  jeśli używamy klauzuli USING, to specyfikujemy kolumnę (jeśli nie – brane są pod uwagę WSZYSTKIE pary o jednakowych nazwach)  istnieje NATURAL JOIN (inner) oraz NATURAL [LEFT|RIGHT|FULL] OUTER select * from pracownik NATURAL JOIN dzial USING (ID_dzial);  NATURAL JOIN wymaga odpowiedniego nazywania kolumn  (jest to potencjalnie niebezpieczne dla nieuważnego programisty) Create table pracownik ( id int auto_increment primary key, nazwisko char(30), ID_dzial int ); Create table dzial ( ID_dzial int auto_increment primary key, nazwa char(30) );

15 CROSS JOIN  CROSS JOIN zwraca iloczyn kartezjański select * from pracownik CROSS JOIN jezyk select * from pracownik, jezyk | id | imie | nazwisko | placa | id_jez | id | nazwa | | 1 | Jan | Nowak | 3400 | 11 | 11 | polski | | 2 | Ewa | Malina | 2100 | 11 | 11 | polski | | 3 | Iza | Trus | 4000 | 12 | 11 | polski | | 1 | Jan | Nowak | 3400 | 11 | 12 | angielski | | 2 | Ewa | Malina | 2100 | 11 | 12 | angielski | | 3 | Iza | Trus | 4000 | 12 | 12 | angielski | | 1 | Jan | Nowak | 3400 | 11 | 13 | niemiecki | | 2 | Ewa | Malina | 2100 | 11 | 13 | niemiecki | | 3 | Iza | Trus | 4000 | 12 | 13 | niemiecki |

16 GROUP BY  Rozważmy następującą bazę: create table paragon ( id int auto_increment primary key, numer char(10), wartosc numeric(5,2), data_zakupu date, id_kli int ); create table klient ( id int auto_increment primary key, nazwa char(15) );

17 GROUP BY  Dotychczas tworzyliśmy po prostu tablicę wynikową za pomocą JOIN: select nazwa, numer, wartosc from klient left outer join paragon on (klient.id=paragon.id_kli); | nazwa | numer | wartosc | | Alfa sp. z o.o. | P001 | | | Alfa sp. z o.o. | P002 | | | Alfa sp. z o.o. | P003 | | | Alfa sp. z o.o. | P008 | 45 | | Beta SA | P004 | | | Beta SA | P005 | 70 | | Beta SA | P006 | 19.2 | | Beta SA | P007 | 30 | | Gamma Inc. | NULL | NULL |  Teraz chcemy przeprowadzić operacje na grupach danych

18 GROUP BY select nazwa, wartosc from klient left outer join paragon on (klient.id=paragon.id_kli); | nazwa | wartosc | | Alfa sp. z o.o. | | | Alfa sp. z o.o. | | | Alfa sp. z o.o. | | | Alfa sp. z o.o. | 45 | | Beta SA | | | Beta SA | 70 | | Beta SA | 19.2 | | Beta SA | 30 | | Gamma Inc. | NULL | select klient.id, nazwa, sum(wartosc) from klient left outer join paragon on (klient.id=paragon.id_kli) GROUP BY klient.id; | id | nazwa | sum(wartosc) | | 1 | Alfa sp. z o.o. | | | 2 | Beta SA | | | 3 | Gamma Inc. | NULL |  GROUP BY pozwala na zastosowanie SUM do grup (a nie całości) select sum(wartosc) from klient left outer join paragon on (klient.id=paragon.id_kli); | sum(wartosc) | | |

19 GROUP  Klauzuli GROUP BY używamy ze wszystkimi funkcjami, które mają działać na grupach danych i wyliczać dla każdej grupy reprezentującą ją wartość  Wyliczoną wartość nazywamy agregatem, a funkcje – funkcjami agregującymi  Funkcje agregujące to m.in. COUNT, MAX, MIN, SUM i AVG # wylicz wartość zakupów # dla każdej z firm select nazwa, sum(wartosc) from klient left outer join paragon on (klient.id=paragon.id_kli) group by klient.id; # wylicz średni zakup # dla każdej z firm select nazwa, avg(wartosc) from klient left outer join paragon on (klient.id=paragon.id_kli) group by klient.id; # jaki jest największy zakup # każdej z firm select nazwa, max(wartosc) from klient left outer join paragon on (klient.id=paragon.id_kli) group by klient.id; # ile zakupów zrobiła # każda z firm select nazwa, count(wartosc) from klient left outer join paragon on (klient.id=paragon.id_kli) group by klient.id;

20 HAVING  Klauzula HAVING pozwala wyfiltrować krotki, dla których agregat spełnia określony warunek (agregat – czyli WARTOŚĆ REPREZENTUJĄCA KAŻDĄ Z GRUP) select nazwa, sum(wartosc) from klient left outer join paragon on (klient.id=paragon.id_kli) group by klient.id HAVING sum(wartosc)> | nazwa | sum(wartosc) | | Alfa sp. z o.o. | | | nazwa | wartosc | | Alfa sp. z o.o. | | | Alfa sp. z o.o. | | | Alfa sp. z o.o. | | | Alfa sp. z o.o. | 45 | | Beta SA | | | Beta SA | 70 | | Beta SA | 19.2 | | Beta SA | 30 | | Gamma Inc. | NULL | | nazwa | sum(wartosc) | | Alfa sp. z o.o. | | | Beta SA | | | Gamma Inc. | NULL | HAVING GROUP + SUM

21 HAVING vs WHERE  WHERE jest filtrem dla danych PRZED agregacją,  HAVING jest filtrem dla agregatów (wyników PO agregacji) select nazwa, sum(wartosc) from klient left outer join paragon on (klient.id=paragon.id_kli) WHERE wartosc>50 group by klient.id HAVING sum(wartosc)>200; | nazwa | wartosc | | Alfa sp. z o.o. | | | Alfa sp. z o.o. | | | Beta SA | | | Beta SA | 70 | WHERE | nazwa | wartosc | | Alfa sp. z o.o. | | | Beta SA | | | nazwa | wartosc | | Alfa sp. z o.o. | | | Alfa sp. z o.o. | | | Alfa sp. z o.o. | | | Alfa sp. z o.o. | 45 | | Beta SA | | | Beta SA | 70 | | Beta SA | 19.2 | | Beta SA | 30 | | Gamma Inc. | NULL | GROUP+SUM HAVING | Alfa sp. z o.o. | |

22 JOIN z użyciem aliasów  Użycie aliasów pozwala za skrócenie długich zapytań JOIN (ale czasem może zmniejszyć czytelność polecenia) select nazwa, sum(wartosc) from klient left outer join paragon on (klient.id=paragon.id_kli) group by klient.id HAVING sum(wartosc)>300 select nazwa, sum(wartosc) from klient as k left outer join paragon as p on (k.id=p.id_kli) group by k.id HAVING sum(wartosc)>300 select nazwa, sum(wartosc) as ile from klient as k left outer join paragon as p on (k.id=p.id_kli) group by k.id HAVING ile>300

23 JOIN przez kilka tabel REDUNDANCJA Ta kolumna jest niepotrzebna, dlatego należy ją usunąć!

24 JOIN przez kilka tabel  Gdzie sprzedajemy (ile faktur w poszczególnych miastach) select miasto.nazwa, count(faktura.id) from miasto left outer join kupujacy on (miasto.id=kupujacy.id_mia) left outer join faktura on (kupujacy.id=faktura.id_kup) group by miasto.id | nazwa | count(faktura.id) | | Poznan | 4 | | Krakow | 3 | | Gdansk | 2 | | Warszawa | 4 | | Szczecin | 2 | | Tczew | 2 | | Sanok | 2 | | Radom | 0 |

25 JOIN przez kilka tabel  Jakie są wartości poszczególnych faktur? select faktura.numer, sum(linia.ilosc*towar.cena) as wartosc from faktura left outer join linia on (faktura.id=linia.id_fak) left outer join towar on (linia.id_tow=towar.id) group by faktura.id | numer | wartosc | | FV | | | FV | | | FV | | (...) | FV | | | FV | | | FV | | | FV | |

26 JOIN przez kilka tabel  Ile faktur wystawili sprzedawcy? select sprzedawca.nazwisko, count(faktura.numer) as ile from sprzedawca left outer join faktura on (sprzedawca.id=faktura.id_spr) group by sprzedawca.id | nazwisko | ile | | Nowak | 4 | | Kuna | 2 | | Trus | 2 | | Pokora | 2 | | Gisz | 4 | | Wist | 1 | | Kunera | 1 | | Pokora | 1 |

27 Postaci normalne O dobrym i złym projektowaniu baz danych

28  Dobry diagram baz danych powinien:  umożliwiać szybkie wyszukiwanie danych  zapewniać łatwą modyfikowalność  minimalizować szanse na wprowadzenie niespójności  zapewniać brak redundancji

29  Problemy:  jak wyszukać pracowników z Gdańska: SELECT * from PRACOWNIK WHERE adres like '%gdańsk%'  jak wyszukać pracowników z Wydziału A SELECT * from PRACOWNIK WHERE dzial like '%A%'  Powyższy diagram nie jest BŁĘDNY – jest MARNEJ JAKOŚCI

30  Jak dobrze projektować ERD?  Jak oceniać jakość diagramu ERD?  POSTAĆ NORMALNA: to zbiór własności, którymi muszą się charakteryzować dane, aby mogły być uznane za znormalizowane do danej postaci. Mówimy: te dane są (lub nie) w pierwszej (drugiej, trzeciej...) postaci normalnej.

31 1NF  Pierwsza postać normalna (1NF) wg Ch. Date:  Zbiór danych jest w 1NF wtedy, gdy:  nie ma powtarzających się krotek  każdy atrybut jest jednowartościowy (czyli, że w danym polu można zapisać tylko jedną wartość z dopuszczalnego zbioru)  nie ma wartości pustych (NULL)  Wersja dla teoretyków:  „zbiór danych jest w pierwszej postaci normalnej wtedy i tylko wtedy, gdy istnieje taka relacja, z którą zbiór ten jest izomorficzny

32 1NF  1NF: nie ma powtarzających się krotek:  zapewniamy przez UNIQUE albo przez kolumnę ID:  1NF: jednowartościowość atrybutów i NULL: ?

33  postulat Codda do 1NF:  dane powinny być "atomowe" (niepodzielne)  1 NF w wersji Codda:  rekordy (krotki) są rozróżnialne  atrybuty są atomowe  UWAGA: czy DATE albo CHAR(50) jest atomem?

34 2NF  2NF odnosi się do wykluczenia redundancji ?  W jaki sposób opisać to zjawisko formalnie?  klucz kandydujący - jest to każdy atrybut (lub najmniejsza z możliwych grupa atrybutów), których wartość jest unikalna w danej tabeli  klucz główny – arbitralnie wybrany klucz kandydujący  Zależność funkcyjna pomiędzy dwoma atrybutami (kolumnami tabeli) A i B oznacza, że dla każdej wartości atrybutu A występuje zawsze jedna wartość B

35 Zależność funkcyjna atrybutów encji  Zależność funkcyjna pomiędzy dwoma atrybutami (kolumnami tabeli) A i B oznacza, że dla każdej wartości atrybutu A występuje zawsze jedna wartość B  B1 = f(A1) ale B2 nie jest f(A2)

36 2 NF  Jakie są klucze kandydujące tabeli:  Tabela jest w 2NF wtedy i tylko wtedy gdy: 1. jest w 1NF 2. żaden z atrybutów, które nie wchodzą w skład klucza kandydującego nie jest funkcjonalnie zależny od części tego klucza (inaczej: żaden z atrybutów nie jest w częściowej zależności funkcyjnej od klucza głównego)  Tabela jest w 2NF wtedy i tylko wtedy gdy (mniej formalnie): 1. jest w 1NF 2. jeżeli weźmiemy dowolny klucz kandydujący i dowolny atrybut nie będący jego częścią to atrybut ten nie może być funkcją części klucza kandydującego.

37 2 NF  Sprawdzenie:  klucz kandydujący: (imię, nazwisko, język)  atrybut spoza klucza: miasto  klucz kandydujący vs atrybut: pełna zależność funkcyjna – ZAWSZE (dlaczego?) częściowa zależność funkcyjna – TAK MIASTO=f(imie, nazwisko)  WNIOSEK: relacja nie jest w 2NF

38 1NF  2 NF  Normalizacja do 2NF powoduje powstanie dodatkowych tablic

39 3NF  Trzecia postać normalna jest "silniejszą wersją" 2NF  Tabela jest w 3NF wtedy i tylko wtedy gdy: 1. jest w 2NF 2. nie istnieją przechodnie zależności funkcyjne  Sprawdzenie częściowych zależności funkcyjnych 2NF:  klucz kandydujący: Tor-Rok, atrybuty zewnętrzne: nazwisko, kraj  nazwisko nie jest f(Rok), nazwisko nie jest f(Tor),  kraj nie jest f(Rok), kraj nie jest f(Tor)  2NF

40 3NF  Problem:  Zależność funkcyjna przechodnia:  Kraj = f(Nazwisko)  UWAGA: To nie jest złamanie 2NF, bo ani kraj, ani nazwisko nie są częściami klucza kandydującego  Tak wyglądać może problem wynikający z niespełnienia 3NF:

41 Postaci Normalne - podsumowanie  UWAGA:  postaci normalne można "łamać" – np. świadomie godzić się na wprowadzenie (potencjalnej) niespójności do bazy danych  przykład: utworzenie tabeli przechowującej wartości zagregowane, aktualizowanej po DELETE lub INSERT  przykład: dodanie kolumny kod_miasta obok kolumny miasto  WNIOSKI:  postaci normalne to formalny sposób oceny jakości diagramu  stosujemy je po to, aby sprawdzić jakość naszych danych  nie robimy tego tylko po to, aby robić – możliwe jest złamanie PN, byle ŚWIADOME


Pobierz ppt "Bazy Danych W04: JOIN (złączenia) Wojciech St. Mościbrodzki"

Podobne prezentacje


Reklamy Google