Relacje między tablicami

Relacje między tablicami

Powiązania pomiędzy tablicami związane są z pojęciami klucza głównego i klucza obcego.

Klucz główny jest atrybutem (kolumną) zapewniającym unikalność rekordu w obrębie tabeli, w której wystepuje. W relacyjnej bazie danych, każda relacja (tabela) musi zawierać klucz główny.

Klucz obcy jest kolumną, która nie musi być unikatowa w obrębie tabeli, w której występuje, ale jest unikatowa w tabeli, do której odnosi się ta kolumna. Oznacza to więc, że musi istnieć tabela, w której występuje kolumna będąca kluczem głównym, do której odnosi się kolumna będąca kluczem obcym w innej tabeli. Należy zauważyć, że nie zachodzi zależność odwrotna, tzn. w tabeli z kluczem głównym, do którego odnosi się klucz obcy z innej tabeli, nie musi istnieć kolumna, będąca kluczem obcym dla innej tabeli.

Na tablicę z kluczem głównym mówi się potocznie tablica rodzic, natomiast na tablicę z kluczem obcym mówi sie potocznie tablica dziecko.

Przykład:

Mamy cztery tablice dotyczące realizacji zamówień pewnych towarów. W każdej z tych tablic występuje co najmniej jeden klucz główny i/lub obcy. Oto te tablice:

Tabela zamowienia zawiera klucz główny id_zamowienia oraz klucz obcy id_klienta, który odwołuje się do klucza głównego id_klienta w tabeli klient.

Tabela towary zawiera klucz główny id_towaru, który jest kluczem obcym w tabeli dostawy.

Tabela dostawy jest tutaj dość specyficzną tabelą. Zawiera ona bowiem tylko dwie kolumny, z których każda jest kluczem obcym. Kolumna id_zamowienia odwołuje się do klucza głównego w tabeli zamowienia, natomiast klumna id_towaru odwołuje się do klucza głównego w tabeli towary.

Choć nie ma tu takiego przykładu, to możliwe jest utworzenia klucza głównego, który złożony jest z kilku kolumn. Wtedy unikalność rekordów jest zapewniona dzięki istnieniu unikalnych par danych. Możliwe jest zatem również zdefiniowanie w taki sposób klucza obcego.

Często jest tak, że klucz główny w tabeli jest jednocześnie kluczem obcym. Wtedy klucz taki identyfikuje unikalnie rekordy w tabeli, jak również odwołuje się do rekordów z innej tabeli. Zwykle wskazuje to na relację jeden do wielu pomiędzy wierszami dwóch tabel.

Co to wszystko nam daje?

Jeśli w tabeli zamowienia mamy w polu id_klienta wartość, która nie odpowiada żadnej z wartości klucza głównego w tabeli klient to mamy problem. Oznacza to bowiem, że mamy zamówienie i nie wiemy kto je złożył. Co prawda, możemy w aplikacji, która z takiej bazy danych korzysta, wprowadzić odpowiednie sprawdzenie i reakcję na tego typu błędy, to jednak dużo bezpieczniej i wygodniej jest dbać o integralność danych w samej bazie danych. A zatem definiowanie relacji pomiędzy danymi w różnych tabelach umożliwia nam zachowanie logicznej integralności danych, w taki sposób aby można było bezpiecznie i logicznie (a jednocześnie nie powtarzając danych) wprowadzać i przechowywać dane i korzystać z nich.

Dane w takich tabelach.

Sprawdźmy jakie kluczowe dane znajdują się w tablicy zamowienia

mysql> SELECT id_zamowienia, id_klienta FROM zamowienia;
+---------------+------------+ 
| id_zamowienia | id_klienta | 
+---------------+------------+ 
|             1 |          3 | 
|             2 |          8 | 
|             3 |          8 | 
|             4 |          9 | 
|             5 |         16 | 
|             6 |         18 | 
+---------------+------------+ 

Jak widać, mamy w tabeli zamowienia 6 wierszy, w których wartości z kolumny id_klienta odwołują się do danych z kolumny o takiej samej nazwie w tabeli klient. W tabeli zamowienia wystepują odwołania do klientów o numerach 3,8,9,16,18. Odwołania dotyczą tylko pięciu wierszy ponieważ wiersze z identyfikatorami id_zamowienia o wartościach 2 i 3 odwołują się do tego samego klienta. Domyślamy się więc, że klient o identyfikatorze id_klienta o wartości 8 złożył dwa zamówienia.

Spróbujmy teraz usunąc z tabeli klient wiersz o identyfikatorze id_klienta równym 3:

mysql> DELETE FROM klient WHERE id_klienta='3';
ERROR 1030: Got error 1000011 from table handler

MySQL otrzymał od procedury obsługującej tabele sygnał o istnieniu wiersza podrzędnego i zablokował usuwanie rekordu. Bez problemu natomiast możemy usuwac wiersze, które nie posiadają wierszy podrzędnych.

mysql> DELETE FROM klient WHERE id_klienta='4';
Query OK, 1 row affected (0.00 sec)

Jak widać, tym razem można było bez problemów usunąć odpowiedni rekord z tabeli klient, gdyż w tym przypadku do wiersza o identyfikatorze id_klienta o wartości równej 4 nikt nie odwoływały się żadne inne dane z innych tabel.

Sprawdzanie dotyczy również prób wstawienia do tabeli zamowienia wiersza, który odwołuje się do danych z tabeli klient.

mysql> INSERT INTO zamowienia(id_zamowienia,id_klienta)
       VALUES(DEFAULT,'250');
ERROR 1030: Got error 1000010 from table handler

Jak widać wystąpi błąd podczas próby wstawienia rekordu do tablicy zamowienia, jeśli w tablicy klient nie będzie odpowiedniego rekordu o identyfikatorze id_klienta równym 250. Wynika to bezpośrednio ze zdefiniowania kluczy obcych i głównych w tablicach zamowienia oraz klient.

Jeszcze jeden ważny problem

Czasasmi zdarza się, że musimy zmienić wartości kluczy głównych id_klienta w tabeli klient, a do nich odwołują sie przecież klucze obce z tabeli zamowienia. Nie da się łatwo przeprowadzić tej operacji, gdyż klucz obcy z tabeli zamowienia zablokuje tą operację z powodu braku odpowiedniego wiersza w tabeli klient.

Nie możemy zmienić wartości id_klienta w tabeli zamowienia, ponieważ pozycja w tabeli klient jeszzce nie istnieje; nie możemy również zmienić wartości w tabeli klient, ponieważ do tej wartości odwołuje się klucz obcy id_klienta z tabeli zamowienia.

Jak sobie z tym zatem poradzić? Standard SQL wprowadza słowo DEFERRABLE dodawane na końcu definicji klucza obcego podczas definicji tablicy (lub zmiany tej definicji). Jeśli zastosuje się opcję DEFERRABLE, wtedy baza danych będzie pozwalała na naruszenie klucza obcego ale jedynie wewnątrz transakcji. Jak wiadomo, transakcje są grupami instrukcji SQL, które musza być wykonane w całości lub niewykonane w ogóle. Z tego powodu możemy rozpocząć transakcję, zmienić wartość id_klienta w tabeli klient, nastepnie zmienić id_klienta w wierszach tabeli zamowienia, które odwoływały się do poprzedniej wartości i zatwierdzić transakcję.

Jednak, z tego co wiadomo, MySQL nie umożliwia stosowanie opcji DEFERRABLE podczas definiowania kluczy obych. Zamiast tego wprowadza opcje ON DELETE CASCADE lub ON DELETE SET NULL oraz ON UPDATE CASCADE lub ON UPDATE SET NULL.

Jeśli w definicji klucza obcego dodamy ON DELETE CASCADE i spróbujemy usunąć wiersz z tabeli rodzic, wtedy procedury osbługujące tabele (relacyjne InnoDB) automatycznie usuną też wiersze w tabeli dziecko, które zawierają w kolumnach będących kluczami obcymi takie same wartości jak te, które były kluczami głównymi w tablicy rodzic, i które zamierzamy usunąć. jeśli w definicji klucza obcego dodamy ON DELETE SET NULL i spróbujemy usunąć wiersz z tabeli rodzic, wtedy procedury osbługujące tabele (relacyjne InnoDB) automatycznie zmienią dane w rekordach z kluczami obcymi w tabeli dziecko nadając tym polom wartość NULL nie bacząc nawet na deklarację SET DEFAULT podczas definicji tablicy.

Podobnie działają polecenia ON UPDATE CASCADE oraz ON UPDATE SET NULL.

Jest to więc dośc wygodne rozwiązanie, gdyż w przypdaku definicji kluczy głównych i obcych w naszych tabelach relacyjnych, podczas ich modyfikacji zostanie zachowana logiczna struktura danych. Trzeab jednak mieć świadomość rozwiązań jakie stosuje MySQL podczas próby zmiany lub usuwania kluczy głównych.

Aby powiedzieć o relacjach w MySQL trzeba najpierw powiedzieć o tablicach w MySQL. A zatem:

Tablice w MySQL

MySQL udostępnia dwa rodzaje tablic: transakcyjne i nietransakcyjne.

Podczas tworzenia tablicy, można zadeklarować jej konkretny typ. Należy w tym celu dodać jedno z dwóch następujących wyrażeń podczas pisania polecenia CREATE TABLE: ENGINE = INNODB; lub TYPE = MEMORY; (gdzie INNODB, MEMORY są dwoma rodzajami tablic wymienionymi wyżej).

Na przykład:

CREATE TABLE tab (i INT) ENGINE = INNODB;
CREATE TABLE tab (i INT) TYPE = MEMORY;

Jeśli ominiemy opcję ENGINE lub TYPE, wtedy domyślnym rodzajem tablicy, który zostanie utworzony poleceniemm CREATE TABLE będzie typ zdefiniowany w zmiennej table_type (najczęściej jest to typ MyISAM).

Aby zmienić rodzaj istniejącej już tablicy, można posłużyć się poleceniem ALTER TABLE, na przykład:

ALTER TABLE tab ENGINE = MYISAM;
ALTER TABLE tab TYPE = BDB;

Jeśli spróbujemy urzyć tablicy takiego typu, który nie został wkompilowany w MySQL-a (bo na przykład podczas instalacji nie zadano sobie trudu), wtedy MySQL nie zgłosi błędu, tylko utworzyzamiennie tablicę typu MYISAM i zwróci ostrzerzenie (ang. warning) o tym fakcie.

MySQL zawsze tworzy pliki `.frm', które przechowują definicję tablicy i definicje kolumn. Indeksy i dane mogą być przechowywane w jednym lub kilku inyych plikach, zależnie od rodzaju tablicy. Serwer bazy danych tworzy pliki `.frm' niezależnie od systemu składowania danych na poziomie zwyczajnych operacji składowania wykonywanych przez bazę danych.

Każda baza dnych może zawierać tablice różnego typu. Nie ma ograniczenia do jednego typu tablic w jednej bazie danych.

Tablice transakcyjne mają względem tablic nietransakcyjnych wiele zalet:

Tablice nietrasakcyjne mają jednak pewne zalety względem tablic transakcyjnych. Wszystkie one wynikają z braku narzutu mnogości operacji związanych z transakcjami.

Można zatem kombinować dwa rodzaje tablic (transakcyjnych i nietransakcyjnych) nawet w tym samym wyrażeniu SQL, w celu uzyskania jak najlepszych rezultatów, tzn. bezpieczeństwa i szybkości jednocześnie. Jednak trzeba zaznaczyć, że podczas transakcji z wyłączoną opcją autocommit, zmiany w tablicach nietransakcyjnych i tak są nadal wykonywane automatycznie, tak, jakby opcja autocommit była włączona. Nie można zatem cofnąć zmian.

Tworzenie, usuwanie i zmiana struktury tablic w MySQL

Składnia polecenia CREATE TABLE jest następująca

CREATE
  [TEMPORARY] TABLE [IF NOT EXISTS] nazwa_tablicy
  [(definicja_tabeli,...)]
  [opcje] [wyrazenie_select];

lub

CREATE
  [TEMPORARY] TABLE [IF NOT EXISTS] nazwa_tab
  [(] LIKE nazwa_innej_tab [)];
definicja_tabeli
  definicja_kolumny
 | [CONSTRAINT [symbol]] PRIMARY KEY [typ_indeksu] (nazwa_kol,...)
 | KEY [nazwa_indeksu] [typ_indeksu] (nazwa_kol,...)
 | INDEX [nazwa_indeksu] [typ_indeksu] (nazwa_kol,...)
 | [CONSTRAINT [symbol]] UNIQUE [INDEX]
    [nazwa_indeksu] [typ_indeksu] (nazwa_kol,...)
 | [FULLTEXT|SPATIAL] [INDEX] [nazwa_indeksu] (nazwa_kol,...)
 | [CONSTRAINT [symbol]] FOREIGN KEY
    [nazwa_indeksu] (nazwa_kol,...) [definicja_relacji]
 | CHECK (expr)
definicja_kolumny:
  nazwa typ [NOT NULL | NULL] [DEFAULT wartosc_domyslna]
    [AUTO_INCREMENT] [[PRIMARY] KEY] [COMMENT 'string']
    [definicja_relacji]
typ:
   TINYINT[(dlugosc)] [UNSIGNED] [ZEROFILL]
  | SMALLINT[(dlugosc)] [UNSIGNED] [ZEROFILL]
  | MEDIUMINT[(dlugosc)] [UNSIGNED] [ZEROFILL]
  | INT[(dlugosc)] [UNSIGNED] [ZEROFILL]
  | INTEGER[(dlugosc)] [UNSIGNED] [ZEROFILL]
  | BIGINT[(dlugosc)] [UNSIGNED] [ZEROFILL]
  | REAL[(dlugosc,dziesietne)] [UNSIGNED] [ZEROFILL]
  | DOUBLE[(dlugosc,dziesietne)] [UNSIGNED] [ZEROFILL]
  | FLOAT[(dlugosc,dziesietne)] [UNSIGNED] [ZEROFILL]
  | DECIMAL(dlugosc,dziesietne) [UNSIGNED] [ZEROFILL]
  | NUMERIC(dlugosc,dziesietne) [UNSIGNED] [ZEROFILL]
  | DATE
  | TIME
  | TIMESTAMP
  | DATETIME
  | CHAR(dlugosc) [BINARY | ASCII | UNICODE]
  | VARCHAR(dlugosc) [BINARY]
  | TINYBLOB
  | BLOB
  | MEDIUMBLOB
  | LONGBLOB
  | TINYTEXT
  | TEXT
  | MEDIUMTEXT
  | LONGTEXT
  | ENUM(wart1,wart2,wart3,...)
  | SET(wart1,wart2,wart3,...)
definicja_relacji:
  REFERENCES nazwa_tabeli [(nazwa_kol,...)]
    [MATCH FULL | MATCH PARTIAL | MATCH SIMPLE]
    [ON DELETE reakcja]
    [ON UPDATE reakcja]
reakcja:
  RESTRICT | CASCADE | SET NULL | NO ACTION | SET DEFAULT
opcje:
   {ENGINE|TYPE} = {BDB|HEAP|ISAM|InnoDB|MERGE|MRG_MYISAM|MYISAM}
  AUTO_INCREMENT = wartosc
 | AVG_ROW_LENGTH = wartosc
 | CHECKSUM = {0 | 1}
 | COMMENT = 'string'
 | MAX_ROWS = wartosc
 | MIN_ROWS = wartosc
 | PACK_KEYS = {0 | 1 | DEFAULT}
 | PASSWORD = 'string'
 | DELAY_KEY_WRITE = {0 | 1}
 | ROW_FORMAT = { DEFAULT | DYNAMIC | FIXED | COMPRESSED }
 | RAID_TYPE = { 1 | STRIPED | RAID0 }
  RAID_CHUNKS = wartosc
  RAID_CHUNKSIZE = wartosc
 | UNION = (nazwa_tabeli[,nazwa_tabeli]...)
 | INSERT_METHOD = { NO | FIRST | LAST }
 | DATA DIRECTORY = 'sciezka_bezwzgledna_do_katalogu'
 | INDEX DIRECTORY = 'sciezka_bezwzgledna_do_katalogu'
 | [DEFAULT] CHARACTER SET nazwa_kodowania [COLLATE nazwa_porownywania]
wyrazenie_select:
  [IGNORE | REPLACE] [AS] SELECT ... (jakies_wyrazenie_select)

Polecenie CREATE TABLE tworzy tablicę o zadanej nazwie. Aby można było utworzyć tablicę w danej bazie danych, trzeba posiadać odpowiednie przywileje.

Domyślnie tabela jest tworzona w bierzącej bazie danych. Jeśli tabela o podanej nazwie istnieje lub jeśli nie wybrano bazy danych lub też w przypadku jeśli podana baza danych nie istnieje, wówczas podczas tworzenia tabeli jest zgłaszany błąd.

Można zatem używać notacji krokpowej. Na przykład wyrażenie baza_danych.nazwa_tabeli jest poprawnym wyrażeniem i oznacza tabelę o nazwie nazwa_tabeli w bazie danych baza_danych. Nie potrzeba więc w takim wypadku wybierac wcześniej bazy_danych osobnym poleceniem. Jeśli chcemy w wypadku notacji kropkowej używać cytowania za pomocą apostrofów, musimy pamiętać, o osobnym cytowaniu nazwy bazy danych i nazwy tabeli. Zatem, poprawnie jest `baza`.`tabela` podczas gdy niepoprawnie jest `baza.tabela`.

Trochę o definicji kolumn:

W danej tabeli może istnieć tylko jedna kolumna z atrybutem AUTO_INCREMENT.

Dla kompatybilności z aplikacjami ODBC, MySQL wprowadził możliwość znalezienia ostatnio wprowadzonej wartości AUTO_INCREMENT za pomocą następującego polecenia:

SELECT * FROM tabela WHERE auto_kol IS NULL
mysql> CREATE TABLE tab (c CHAR(20) CHARACTER SET utf8 COLLATE utf8_bin);
mysql> SHOW CHARACTER SET;
mysql> SHOW COLLATION LIKE 'latin2%';

Jeśli nie zadamy explicite wartości domyślnej a jedynie słowo DEFAULT wtedy wartość domyślna zostanie wyznaczona według następujących reguł:

Fragment polecenia, który służy do zadeklarowania kolumny jako klucza obcego w innej tabeli jest umieszczany po deklaracji wszystkich kolumn i posiada następującą składnię:

mysql> [CONSTRAINT [nazwa]] FOREIGN KEY (lista_kolumn)
       REFERENCES nazwa_tabeli_obcej(lista_kolumn);

Należy zauważyć, że w tym poleceniu wystąpienie [CONSTRAINT [nazwa]] jest opcjonalne.

W przypadku tabel typu InnoDB musi być spełniony dodatkowy warunek, mianowicie kolumna, dla której tworzymy klucz obcy musi posiadać indeks. A zatem najpierw dodajemy indeks dla tej kolumny, a dopiero później definiujemy klucz główny.

Oto proste przykłady definiowania relacji pomiędzy tablicami w MySQL.
Na początku proste użycie tablicy "rodzic" i tablicy "dziecko" i powiązanie danych z tablicy "dziecko" z danymi z tablicy "rodzic" poprzez klucz obcy w jednej kolumnie tablicy "dziecko"

Definicja tablicy "rodzic":
mysql> CREATE TABLE rodzic(

         id INT NOT NULL,

         PRIMARY KEY (id)

       )TYPE=InnoDB;
Definicja tablicy "dziecko":
mysql> CREATE TABLE dziecko(

         id INT,
         rodzic_id INT,

         INDEX rodzic_ind(rodzic_id),
         FOREIGN KEY (rodzic_id) REFERENCES rodzic(id)
         ON DELETE CASCADE

       )TYPE=InnoDB;

W powyższym, najprostszym przykładzie definicji relacji pomiędzy danymi pochodzącymi z różnych tablic, dane z tablicy "dziecko" są zależne od danych z tablicy "rodzic" poprzez parę kluczy głównego i obcego, tj. odpowiednio rodzic.id oraz dziecko.rodzic_id.

Nastepny przykład jest bardziej złożonym przypadkiem definicji relacji, w której jedna z tablic posiada dwa klucze obce, każdy związany z innym kluczem głównym z innej tablicy.

Definicja tablicy powiaty:
mysql> CREATE TABLE powiaty(

         id INT NOT NULL,
         nazwa CHAR(50) NOT NULL,

         PRIMARY KEY (id)

       )TYPE=InnoDB;
Definicja tablicy wojewodztwa:
mysql> CREATE TABLE wojewodztwa(

         id INT,
         nazwa CHAR(50) NOT NULL,

         PRIMARY KEY (id)

       )TYPE=InnoDB;
Definicja tablicy osoba:
mysql> CREATE TABLE osoba(

         id INT,
         imie CHAR(50) NOT NULL,
         nazwisko CHAR(50) NOT NULL,
         adres_wojew INT NOT NULL,
         adres_powiat INT NOT NULL,

         PRIMARY KEY (id),
         INDEX adres_wojew,
         FOREIGN KEY (adres_wojew) REFERENCES wojewodztwa(id)
         ON UPDATE CASCADE ON DELETE RESTRICT,
         INDEX adres_powiat,
         FOREIGN KEY (adres_powiat) REFERENCES powiaty(id)
         ON UPDATE CASCADE ON DELETE RESTRICT

       )TYPE=InnoDB;

Uwaga! Zawsze przed zdefiniowaniem klucza obcego w tabeli należy najpierw utworzyć odpowiedni indeks.
A zatem, zanim użyjemy FOREIGN KEY ... najpierw trzeba użyć INDEX ....

Przykład

Oto zestaw poleceń tworzących tablice relacyjne wraz z połączeniami między nimi dla omówionego wcześniej przypadku zamówień w sklepie.

Są to cztery tablice: klient, zamowienia, towary oraz dostawy. Tablice klient oraz towary nie zawierają definicji kluczy obcych, podczas gdy tablice zamowienia oraz dostawy zawierają klucze obce. Wszystkie tablice, oprócz dostawy zawierają klucze główne.

------------------------------------------------------

CREATE TABLE klient ( 
 
  id_klienta       int auto_increment NOT NULL, 
  nazwa            varchar(30)  NOT NULL, 
  miasto           varchar(50)  NOT NULL, 
  ulica            varchar(50)  NOT NULL, 
  kod_pocztowy     varchar(10)  NOT NULL, 
  telefon          varchar(50)  NOT NULL, 
 
  PRIMARY KEY  (id_klienta), 
  INDEX (id_klienta) 
 
) TYPE=InnoDB; 

------------------------------------------------------

CREATE TABLE zamowienia ( 
 
  id_zamowienia     int  auto_increment NOT NULL, 
  id_klienta        int  NOT NULL, 
  data_zamowienia   date NOT NULL, 
  data_realizacji   date NOT NULL, 
 
  PRIMARY KEY  (id_zamowienia), 
  INDEX (id_zamowienia), 
  INDEX (id_klienta), 
  CONSTRAINT id_klienta_obcy FOREIGN KEY(id_klienta) 
    REFERENCES klient(id_klienta) 
 
) TYPE=InnoDB; 

------------------------------------------------------

CREATE TABLE towar ( 
 
  id_towaru         int  auto_increment NOT NULL, 
  opis_towaru       varchar(50)   NOT NULL, 
  cena_zakupu       numeric(10,2) NOT NULL, 
  cena_sprzedazy    numeric(10,2) NOT NULL, 
 
  PRIMARY KEY  (id_towaru), 
  INDEX (id_towaru) 
 
) TYPE=InnoDB; 

------------------------------------------------------

CREATE TABLE dostawy ( 
 
  id_zamowienia     int  NOT NULL, 
  id_towaru         int  NOT NULL, 
 
  INDEX (id_zamowienia), 
  INDEX (id_towaru), 
  CONSTRAINT id_zamowienia_obcy FOREIGN KEY(id_zamowienia) 
    REFERENCES zamowienia(id_zamowienia), 
  CONSTRAINT id_towaru_obcy FOREIGN KEY(id_towaru) 
    REFERENCES towar(id_towaru) 
 
) TYPE=InnoDB; 

------------------------------------------------------

Warto też zauważyć, że po ostatnim poleceniu podczas definicji struktury tablicy nie występuje przecinek, co wydaje się zupełnie oczywiste, jeśli przyjmie się, że te "wewnętrzne" polecenia w definicji tablicy są jakby elementami listy poleceń rozdzielonymi przecinkami.

PRIMARY KEY jest kluczem unikalnym, zdefiniowanym dla kolumny, w której nie może się znaleźć wartość równa NULL (jeśli nie zdefiniujemy tego podczas tworzenia tablicy, wtedy MySQL zrobi to za nas "po cichu"). Każda tablica może mieć tylko jeden klucz unikalny.

Na przykład:

mysql> SHOW TABLE STATUS FROM nazwa_bazy LIKE 'nazwa_tablicy';

albo też

mysql> SHOW CREATE TABLE nazwa_tablicy;

Podczas tworzenia struktury tablicy można też posłużyć się już istniejącą tablicą i wykorzystać część jej struktury za pomocą komendy SELECT dodanej na końcu polecenia CREATE TABLE

mysql> CREATE TABLE nowa_tablica SELECT * FROM inna_tablicy;

Kolumny z wyrażenia SELECT są dodawane na koniec istniejącej listy kolumn. Na przykład, wyobraźmy sobie, że utworzyliśmy już tablicę o nazwie stara, która wygląda z zawartością mniej więcej następująco:

mysql> SELECT * from stara;
+---+
| n |
+---+
| 1 |
+---+

Następnie utworzymy tablicę, do której zostanie dołączona struktura tablicy stara.

mysql> CREATE TABLE nowa (x INT) SELECT n FROM stara;
Query OK, 1 row affected (0.01 sec)
Records: 1 Duplicates: 0 Warnings: 0

Zobaczmy jak po takiej operacji wygląda nowo utworzona tablica nowa

mysql> SELECT * FROM nowa;
+------+---+
| x    | n |
+------+---+
| NULL | 1 |
+------+---+

Warto zauważyć, że wraz z definicją kolumny została dołączona do nowej tablicy również zawartośc tej tablicy. A ponieważ w tablicy nowa nie było wcześniej żadnych danych, więc w każdym wierszu nowej tablicy w polach, w których nie ma danych znajdą się albo wartości domyślne albo wartości NULL.

Uwaga. Polecenie CREATE TABLE ... SELECT nie utworzy automatycznie indeksów na kopiowanych z innej tabeli kolumnach. Jeśli chcemy mieć indeksy na nowo utworzonych kolumnach tabeli, wtedy musimy to zadać explicite przed poleceniem SELECT

mysql> CREATE TABLE nowa (UNIQUE (n)) SELECT n FROM stara;

Od wersji 4.1 MySQL-a możemy też użyć słowa LIKE w celu utworzenia pustej tablicy na podstawie definicji innej tablicy. Podczas takiego sposobu tworzenia nowej tablicy wszystkie informacje zawarte w oryginalnej tablicy sa kopiowane (również indeksy).

mysql> CREATE TABLE nowa LIKE stara;

Należy pamiętać, że polecenie CREATE TABLE ... LIKE nie kopiuje żadnych danych ze starej tablicy do nowej.

Składnia polecenia DROP TABLE jest następująca

DROP
  [TEMPORARY] TABLE [IF EXISTS] nazwa_tab1 [, nazwa_tab2] ...
  [RESTRICT | CASCADE]

Polecenie DROP TABLE służy do usuwania jednej lub większej ilości tablic.
Uwaga! Usuwane sa wszystkie dane zawarte w usuwanej tablicy.

Składnia polecenia ALTER TABLE jest następująca

ALTER
  [IGNORE] TABLE nazwa_tab
  opis_zmiany [, opis_zmiany] ...

A dokładniej

opis_zmiany:

  ADD [COLUMN] definicja_kolumny [FIRST | AFTER kolumna]
 | ADD [COLUMN] (definicja_kolumny,...)
 | ADD INDEX [nazwa_indeksu] [typ_indeksu] (kolumna,...)
 | ADD [CONSTRAINT [symbol]]
    PRIMARY KEY [typ_indeksu] (kolumna,...)
 | ADD [CONSTRAINT [symbol]]
    UNIQUE [nazwa_indeksu] [typ_indeksu] (kolumna,...)
 | ADD [FULLTEXT|SPATIAL] [nazwa_indeksu] (kolumna,...)
 | ADD [CONSTRAINT [symbol]]
    FOREIGN KEY [nazwa_indeksu] (kolumna,...)
    [definicja_relacji]
 | ALTER [COLUMN] kolumna {SET DEFAULT literał | DROP DEFAULT}
 | CHANGE [COLUMN] stara_nazwa definicja_kolumny
    [FIRST|AFTER nazwa_kolumny]
 | MODIFY [COLUMN] definicja [FIRST | AFTER kolumna]
 | DROP [COLUMN] kolumna
 | DROP PRIMARY KEY
 | DROP INDEX nazwa_indeksu
 | DROP FOREIGN KEY nazwa_symbolu_klucza_obcego
 | DISABLE KEYS
 | ENABLE KEYS
 | RENAME [TO] nowa_nazwa_tabeli
 | ORDER BY kolumna
 | CONVERT TO CHARACTER SET kodowanie [COLLATE nazwa_porówn]
 | [DEFAULT] CHARACTER SET kodowanie [COLLATE nazwa_porówn]
 | DISCARD TABLESPACE
 | IMPORT TABLESPACE
 | opcje_tabeli

Polecenie ALTER TABLE służy do zmian struktury istniejących tablic. Można na przykład dodać lub usunąć kolumny, utworzyć lub usunąć istniejące indeksy, zmienić typ kolumn, zmienić nazwy kolumn, zmienić nazwy tabel lub zmienić typ tabeli.

Składnia odpowiednich poleceń służących do zmiany definicji tablicy jest w wielu przypadkach podobna do polecenia CREATE TABLE

Polecenie ALTER TABLE pracuje na kopii zmienianej tablicy; najpierw tworzy tymczasową kopię oryginalnej tablicy, później dokonuje zmian na kopii, później usuwa tablice oryginalną, a następnie "zmienia nazwę" nowej tablicy. Kiedy ALTER TABLE dokonuje zmian na tablicy tymczasowej, wtedy tablica oryginalna jest cały czas dostępna do czytania, a inne polecenia (zmiana zawartości tablicy) są automatycznie przekierowywane do nowej, zmienionej tablicy.

Na przykład aby usunąć kilka kolumn z tabeli przy pomocy jednego polecenia ALTER TABLE możemy wydać następujące polecenie:

mysql> ALTER TABLE tab DROP COLUMN c, DROP COLUMN d;
mysql> ALTER TABLE tab CHANGE a b INTEGER;
mysql> ALTER TABLE tab CHANGE b b BIGINT NOT NULL;
mysql> ALTER TABLE tab MODIFY b BIGINT NOT NULL;
mysql> ALTER TABLE tab ADD [CONSTRAINT [symbol]]
       FOREIGN KEY (...) REFERENCES ... (...)
mysql> ALTER TABLE tab DROP FOREIGN KEY obcy_klucz_symbol;
mysql> ALTER TABLE tab CONVERT TO CHARACTER SET kodowanie;
mysql> ALTER TABLE tab DEFAULT CHARACTER SET kodowanie;
mysql> ALTER TABLE tab CHANGE c2 c2 BLOB;
mysql> ALTER TABLE tab CHANGE c2 c2 TEXT CHARACTER SET utf8;

Załóżmy, że utworzyliśmy tablicę w następujący sposób

mysql> CREATE TABLE tab1 (a INTEGER, b CHAR(10));

Zmiana nazwy tablicy

mysql> ALTER TABLE tab1 RENAME tab2;

Zmiana typu danych w kolumnach z INTEGER na TINYINT NOT NULL, zostawinie jednak niezmienionej nazwy kolumny, oraz jednocześnie zmiana typu danych w kolumnie CHAR(10) na CHAR(20) i zmiana nazwy kolumny

mysql> ALTER TABLE tab2 MODIFY a TINYINT NOT NULL,
       CHANGE b c CHAR(20);

Dodanie nowej kolumny typu TIMESTAMP do już istniejących

mysql> ALTER TABLE tab2 ADD d TIMESTAMP;

Dodanie indeksów na kolumnach d oraz a

mysql> ALTER TABLE tab2 ADD INDEX (d), ADD INDEX (a);

Usunięcie kolumny o nazwie c

mysql> ALTER TABLE tab2 DROP COLUMN c;

Dodanie nowej kolumny o nazwie c typu AUTO_INCREMENT

mysql> ALTER TABLE tab2 ADD c INT UNSIGNED NOT NULL AUTO_INCREMENT,
       ADD PRIMARY KEY (c);

W powyższym przykładzie zadeklarowano kolumnę jako klucz główny, gdyż kolumny z opcją AUTO_INCREMENT muszą być indeksowane oraz dlatego, że zadeklarowano c jako NOT NULL, gdyż z kolei klucze główne nie mogą być NULL.

Składnia polecenia RENAME TABLE jest następująca

RENAME TABLE
  bierzaca_nazwa_tab1 TO nowa_nazwa_tab1
  [, bierzaca_nazwa_tab2 TO nowa_nazwa_tab2] ...

Polecenie RENAME TABLE służy do zmiany nazwy jednej lub wiekszej ilości tablic.

Jeśli mamy w bazie danych tabelę stara i utworzymy tabelę nowa, która ma taką samą strukture jak struktura tablicy stara ale jest pusta, to możemy zamienić je w nastepujący sposób:

mysql> CREATE TABLE nowa (...);
mysql> RENAME TABLE
       stara TO tymcz,
       nowa TO stara,
       tymcz TO nowa;

Inaczej mówiąc, zmiana nazw tabel jest dokonywana automatycznie, od lewej do prawej.

Za pomocą polecenia RENAME TABLE można też przenieśc tabelę z jednej bazy do drugiej (pod warunkiem, że obie bazy danych rezydują na tym samym systemie plików)

mysql> RENAME TABLE baza1.nazwa1 TO baza2.nazwa2;

Kiedy chcemy użyć RENAME TABLE nie możemy mieć w tym czasie zablokowanego dostępu do tabeli i nie może być żadnych aktywnych transakcji.

Składnia polecenia DESCRIBE jest następująca

{DESCRIBE | DESC} nazwa_tab [nazwa_kol | wyr_reg];

Za pomocą tego polecenia możemy dowiedzieć się o strukturze tablicy.

Skrótem od DESCRIBE jest słowo DESC. Zatem zamiast pisać DESCRIBE nazwa_tab można napisać DESC nazwa_tab.

Polecenie DESCRIBE jest skrótem od SHOW COLUMNS FROM, tak więc można używać zamiennie tych poleceń w celu uzyskania tego samego wyniku.

Podczas wykonywania polecenia DESCRIBE można uzyskać informacje o wybranych kolumnach tablicy a nie wszystkich kolumnach tablicy. W tym celu należy obok nazwy tablicy podać też nazwę kolumny lub też wyrażenie regularne wyr_reg określające, o które kolumny nam chodzi. Parser dokona wtedy dopasowania odpowiednich nazw kolumn do wyrażenia regularnego i przekaże listę kolumn do polecenia DESCRIBE.

Przykład:

mysql> DESCRIBE users;
+--------+----------+------+-----+----------------+
| Field  | Type     | Null | Key | Extra          |
+--------+----------+------+-----+----------------+
| id     | int(11)  |      | PRI | auto_increment |
| sid    | char(64) |      |     |                |
| login  | char(32) |      |     |                |
| ip     | char(32) |      |     |                |
| opened | int(1)   |      |     |                |
| closed | int(1)   |      |     |                |
+--------+----------+------+-----+----------------+
6 rows in set (0.00 sec)

Jak widać, wynikiem jest tabela z kolumnami o nazwach Type, Null, Key, Extra, czasem jest też dodatkowo pole Default.

W polu Type jest typ danych kolumny. W polu Null jest informacja o tym, czy w kolumnie mogą się znaleźć wartości NULL. W polu Extra znajdują się informacje o dodatkowych parametrach stanowiących o właściwości danych w tym polu, na przykład parametr auto_increment. W polu Default znajdują się wartości domyślne, jakie przyjmują dane w tych polach, jeśli nie podamy ich explicite podczas wstawiania rekordów do bazy. W polu Key znajdują się informacje o tym, czy kolumna jest kluczem głównym (PRI) czy też kluczem obcym (MUL) w tabeli.

Polecenia SHOW CREATE TABLE oraz SHOW TABLE STATUS również dostarczają informacji na temat tabel w bazie.

Istnieją też inne polecenia dokonujące sprawdzenia spójności tablic, danych w tych tablicach, i które potrafią naprawić niektóre błędy, które mogą wystąpić w tablicach, na przykład w wyniku nagłego braku zasilania. Do poleceń tych należą:


Wyszukiwarka

Podobne podstrony:
Relacje miedzy zagospodarowaniem przestrzennym a systemem transportowym, Studia, Sem 5, SEM 5 (wersj
5 03 2014 relacja między znakiem, a rzeczywistością
relacje między czowiekiem a Bogiem
ZAINTERESOWANIE DIALOGOWĄ RELACJĄ MIĘDZYLUDZKĄ NA GRUNCIE NAUK SPOŁECZNYCH, NAUKA, WIEDZA
Historia filozofii starożytnej, Relacje między Arystotelesem i Platonem, kontynuacja drugiego żeglow
Historia filozofii starożytnej, Relacje między Arystotelesem i Platonem, kontynuacja drugiego żeglow
FRANCUSKI słówka 20.04.2012 relacje międzyludzkie, rodzina
Model relacji międzyludzkiej Hildegardy Peplau
Pozytywne emocje Jak rozwijac relacje miedzyludzkie
SAMODOSKONALENIE, RELACJE MIEDZYLUDZKIE
Relacje między jednostką a zbiorowością w wierszach Norwida
Jaka zachodzi relacja między zdaniem ogólno, prawo - studia
Terapia psychodynamiczna a relacje międzyludzkie, Psychologia
Relacje między teorią a praktyką, PEDAGOGIKA resocjalizacja
Zaburzenia emocjonalne dzieci i młodzieży. Wpływ relacji między rodzicami
Relacje między psychoanalizą dziecka i dorosłego, psychoanaliza1
zieba - wstep, Stosunki międzynarodowe - całokształt relacji między ich uczestnikami (narodami, pańs
Relacje między Polakami, XIX wiek Polska
kompleks tematyczny 9 Relacje między teorią a praktyką, Szkoła - studia UAM, Pedagogika ogólna dr De

więcej podobnych podstron