README.md 3.16 KB
Newer Older
M1888's avatar
M1888 committed
1 2
# ttzc0800-harkka

M1888's avatar
M1888 committed
3 4
Tietokannat (TTZC0800) kurssin harkkatyö

M1888's avatar
M1888 committed
5
## Suunnitelmavaihe
M1888's avatar
M1888 committed
6 7 8 9 10

**[Vaatimusmäärittelyyn](vaatimusmaarittely.md)** tästä.

Vaatimusmäärittelyn pohjalta nousi ainakin seuraavanlaisia käsitteitä:

M1888's avatar
M1888 committed
11 12 13 14 15 16
- Kaupunki (sisältää areenoja, joukkueilla kotikaupunki)
- Areena (sisältää otteluita)
- Joukkue (sisältää pelaajia)
- Pelaaja (kuuluu joukkueeseen)
- Ottelu (sisältää tapahtumia)
- Tapahtumat (maali & jäähy, eri tauluista)
M1888's avatar
M1888 committed
17

M1888's avatar
M1888 committed
18
## Toteutus
M1888's avatar
M1888 committed
19 20 21 22 23

Lähdettäessä toteuttamaan vaatimusmäärittelyn mukaista ensimmäistä versiota tietokannasta, kannan luonti sujui hyvin ja alustavia tietojakin sai lisättyä. Ongelmat kuitenkin ilmenivät ottelutapahtumia lisätessä. Olin suunnitellut ottelutapahtuman tapahtuma_id:n olevan viittaus jonkin ottelutapahtuman id-tauluun (maali, jäähy, rankkari, aikalisä), ja oikea taulu josta tämä id etsittäisiin pääteltäisiin ottelutapahtuman tyyppi-kentän mukaan.

Tämä ei kuitenkaan onnistunut, vaan MySQL valitti vierasavaimien konfliktista, kun kaikista tauluista ei löytynyktään sopivaa id:tä:

M1888's avatar
M1888 committed
24
```SQL
M1888's avatar
M1888 committed
25 26 27 28 29 30 31
mysql> INSERT INTO ottelutapahtuma (tyyppi, tapahtuma_id, ottelu_id, aika) VALUES
    ->     (2, 1, 1, 3*60+14);
    ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`M1888`.`ottelutapahtuma`, CONSTRAINT `fk_ottelutapahtuma_maali1` FOREIGN KEY (`tapahtuma_id`) REFERENCES `maali` (`maali_id`) ON DELETE NO ACTION ON UPDATE NO ACTION)
```

Takaisin suunnittelupöydän ääreen siis. Seuraava versio oli sellainen, jossa ottelutapahtuma-taulussa on oma erillinen foreign key jokaiselle ottelutapahtumatyypille, ja näistä täytetään rajoitteen avulla vain ja ainoastaan yksi. Taulun pääavain tulee ottelu_id:stä ja tästä yhdestä täytetystä FK:sta.

M1888's avatar
M1888 committed
32 33
Itse kirjoitettu check tätä varten meni näin:

M1888's avatar
M1888 committed
34
```SQL
M1888's avatar
M1888 committed
35 36 37 38 39 40 41 42
  CONSTRAINT `CK_tapahtumaid` CHECK (
    CASE WHEN aikalisa_id IS NULL THEN 0 ELSE 1 END +
    CASE WHEN jaahy_id    IS NULL THEN 0 ELSE 1 END +
    CASE WHEN rankkari_id IS NULL THEN 0 ELSE 1 END +
    CASE WHEN maali_id    IS NULL THEN 0 ELSE 1 END = 1)

```

M1888's avatar
M1888 committed
43 44 45
![](er_v2.png)


M1888's avatar
M1888 committed
46
Mutta edelleen törmättiin samankaltaiseen ongelmaan:
M1888's avatar
M1888 committed
47 48

```SQL
M1888's avatar
M1888 committed
49 50 51
mysql> INSERT INTO ottelutapahtuma (ottelu_id, jaahy_id, aika) VALUES (1, 1, 3*60+14);
ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`M1888`.`ottelutapahtuma`, CONSTRAINT `fk_ottelutapahtuma_aikalisa1` FOREIGN KEY (`aikalisa_id`) REFERENCES `aikalisa` (`aikalisa_id`) ON DELETE NO ACTION ON UPDATE NO ACTION)
```
M1888's avatar
M1888 committed
52 53 54 55 56 57

Googlesta ja StackOverflow'sta aikani luettuani, kokeilin pariakin eri lähestymistapaa:

- Vaihdoin ottelutapahtuma-taulun vierasavaimet UNSIGNED INT -tyyppiin
- Kokeilin määrittää kaikki muut vierasavaimet INSERTin aikana erikseen NULL-arvolle
- Vielä paria erilaista constraintia ja muuta määrettä taululle
M1888's avatar
M1888 committed
58 59

Mikään ei auttanut vaikka tämän piti toimia hyvin. Olin jo varma, että Student-palveimen MySQL on liian vanha ja buginen eikä koodissani mitään vikaa ole. Sitten tajusin vielä kokeilla, että jätän FK-määreet näille ottelutapahtuman eri id:ille, mutta teen taululle erillisen oman id:n primary keyksi, näiden neljän fuusion sijaan. Sillä päästiinkin etenemään.