10.3 Tabulu projektēšana un saites
Stundas uzdevums: Projektēt vairākas saistītas tabulas, izmantojot primārās un ārējās atslēgas.
70 min plāns: Teorija un paraugs (~10 min) · 1. uzdevums (~15 min) - izveido otro tabulu ar ārējo atslēgu · 2. uzdevums (~25 min) - pārbaudi, ko dara ārējā atslēga · 3. uzdevums (~20 min) - novērs datu dublēšanos. Papildu uzdevumu sāc tikai tad, ja pārējie trīs ir gatavi.
Pirms sāc: atver savu datubāzi spele. Šajā stundā no vienas tabulas taisīsi divas, kas saistītas savā starpā.
Teorija: Primārās un ārējās atslēgas
Datubāze ir tikai tik laba, cik labi tā ir projektēta. Galvenie principi:
- Primary Key (PK) - viens lauks, kas unikāli identificē rindu (parasti
id SERIAL). - Foreign Key (FK) - lauks vienā tabulā, kas norāda uz citas tabulas PK.
- Normalizācija - neatkārto vienus un tos pašus datus vairākās tabulās.
-- Spēlētāji un viņu spēles (1 → daudzi)
CREATE TABLE speletaji (
id SERIAL PRIMARY KEY,
vards TEXT NOT NULL UNIQUE
);
CREATE TABLE speles (
id SERIAL PRIMARY KEY,
speletajs_id INTEGER NOT NULL REFERENCES speletaji(id) ON DELETE CASCADE,
punkti INTEGER NOT NULL,
spelets TIMESTAMP DEFAULT NOW()
);
ON DELETE CASCADE - ja izdzēš spēlētāju, automātiski tiek izdzēstas arī viņa spēles.
Praktiskie uzdevumi
1. uzdevums -
Izveido otro tabulu ar ārējo atslēgu
Beigās katra spēle zinās, kuram spēlētājam tā pieder.
- Izveido tabulu
CREATE TABLE speles (. - Pievieno lauku
id SERIAL PRIMARY KEY. - Pievieno lauku
speletajs_id INTEGER NOT NULL REFERENCES speletaji(id). - Pievieno lauku
punkti INTEGER NOT NULL CHECK (punkti >= 0). - Pievieno lauku
spelets TIMESTAMP DEFAULT NOW(). - Izpildi skriptu un pārbaudi tabulu ar
\d speles.
Gatavs, kad: tabula speles eksistē, un speletajs_id ir atzīmēts kā ārējā atslēga.
2. uzdevums -
Pārbaudi, ko dara ārējā atslēga
Beigās tu redzēsi, ka datubāze neļauj izveidot spēli bez spēlētāja.
- Atrodi viena spēlētāja
idarSELECT id, vards FROM speletaji;. - Ievadi spēli šim spēlētājam ar
INSERT. - Mēģini ievadīt spēli ar
speletajs_id = 9999. - Pieraksti, kā sauc kļūdu, kas to neļāva.
- Mēģini izdzēst spēlētāju, kuram ir spēles.
- Pieraksti, kāpēc arī tas neizdodas.
- Pievieno ārējai atslēgai
ON DELETE CASCADEun mēģini vēlreiz.
Gatavs, kad: spēli neizdodas piesaistīt neesošam spēlētājam, bet ar ON DELETE CASCADE spēlētāja dzēšana aizvāc arī viņa spēles.
3. uzdevums -
Novērs datu dublēšanos
Beigās viens un tas pats dati vairs neatkārtosies divās vietās.
- Pieraksti, kas notiktu, ja spēlētāja vārdu glabātu arī tabulā
speles. - Pieraksti, cik vietās būtu jālabo vārds, ja spēlētājs to nomainītu.
- Izpildi vaicājumu, kas parāda spēles kopā ar spēlētāja vārdu no otras tabulas.
- Pārliecinies, ka vārds tabulā
spelesnav glabāts. - Nomaini viena spēlētāja vārdu ar
UPDATE. - Izpildi vaicājumu vēlreiz un pārbaudi, ka jaunais vārds parādās visur.
- Pieraksti vienu secinājumu: ko nozīmē neatkārtot datus.
Gatavs, kad: nomainot vārdu vienā vietā, tas mainās visos rezultātos, jo tas glabājas tikai vienā tabulā.
Papildu uzdevums - Pievieno trešo tabulu
Ja pamatdarbs ir gatavs, sadali spēles pa veidiem.
- Izveido tabulu
speles_veidiaridunnosaukums. - Ievadi tajā trīs spēļu veidus.
- Pievieno tabulai
speleslaukuveids_idar ārējo atslēgu. - Atjaunini esošās spēles ar kādu veidu.
- Pārbaudi, ka nevar ievadīt neesošu veidu.
Gatavs, kad: katrai spēlei ir veids, un neesoša veida ievade tiek noraidīta.
Biežākās kļūdas
- FK norāda uz neeksistējošu rindu: Vispirms ievadi vecāku tabulā, tad bērnu.
- Aizmirsts CASCADE: Bez tā nevarēsi dzēst vecāku rindas, kamēr ir bērnu rindas.
- Daudzi-pret-daudziem bez saites tabulas: NEKAD nelieto FK masīvu - vienmēr trešo tabulu.
Koda piemērs
CREATE TABLE speletaji (
id SERIAL PRIMARY KEY,
vards TEXT NOT NULL UNIQUE
);
CREATE TABLE speles (
id SERIAL PRIMARY KEY,
speletajs_id INTEGER NOT NULL REFERENCES speletaji(id) ON DELETE CASCADE,
punkti INTEGER NOT NULL CHECK (punkti >= 0),
spelets TIMESTAMP DEFAULT NOW()
);
INSERT INTO speletaji (vards) VALUES ('Anna'), ('Jānis');
INSERT INTO speles (speletajs_id, punkti) VALUES (1, 120), (1, 85), (2, 200);
3 spēļu rezultāti pievienoti.