This post comes from the first version of this blog.
Please send me an email if anything needs an update. Thanks!

Powoli wyjaśnia się moja sytuacja na uczelni, także mam czas na opisywanie bardziej ambitnych problemów. Dzisiejszy wpis sponsoruje przedmiot Hurtownie i Eksploracja Danych, w ramach którego w tym semestrze naszym zadaniem było m. in. zaprojektowanie rzeczonej hurtowni. Ze względu na to, że uwielbiam przedmioty pozwalające wykorzystać posiadaną wiedzę w praktyce, z przyjemnością zająłem się wykonaniem projektu. ;]

Problem: Nie ma to jak zrozumiałe nazwy błędów.

Strukturę bazy danych obsługującej hurtownię projektowałem w narzędziu MySQL WorkBench, które z tego miejsca szczerze polecam - jak na darmowe oprogramowanie jest naprawdę bardzo solidnym produktem. Po przemyśleniu całego zadania utworzyłem kilkanaście połączonych relacjami tabel i zadowolony z ładnego obrazka [eksport diagramu do pliku PNG jest po prostu genialny] przystąpiłem do pisania sprawozdania.

Po wykonaniu części opisowej przypomniałem sobie, że trzeba jeszcze wstawić kod tworzący całą strukturę [zestaw zapytań CREATE TABLE wraz z odpowiednimi ALTER TABLE dla relacji]. Skonfigurowałem więc połączenie do localhosta w WorkBenchu i kazałem mu zsynchronizować strukturę modelu, aby potem wyeksportować całość poprzez phpMyAdmina. Początkowo nie spojrzałem na listę tabel, jakie zamierza przetworzyć, kliknąłem tylko “next” i po chwili zostałem poinformowany o rzekomym “sukcesie” mojego żądania.

Przywołałem okno Firefoksa, spojrzałem na strukturę bazy i nieco zdziwiony zobaczyłem tylko kilka tabel “liści”, nie posiadających żadnych kluczy obcych. “No cóż, zdarza się” - pomyślałem i spróbowałem stworzyć brakujące tabele ręcznie, kopiując kod SQL z diagramu. Już podczas tworzenia jednej z pierwszych tabel MySQL zaprotestował, twierdząc, że:

#1005 - Can't create table '.\[baza]\[tabela].frm' (errno: 121)
Nie ma to jak zrozumiałe nazwy błędów, prawda?

Rozwiązanie: Nazwy kluczy obcych muszą być unikalne w skali bazy danych.

Szczerze mówiąc, pierwsze co przyszło mi do głowy, to właśnie sprawdzenie kluczy obcych [muszę się w końcu nauczyć, żeby używać terminu "klucz obcy", bo zazwyczaj wykorzystuję dosłowne pojęcie "kluczy zagranicznych", co pozytywnie wpływa na humor rozmówców ;]]. Nie zawsze pierwsze skojarzenie źródła problemu jest poprawne, tym razem jednak się udało. Fragment wygenerowanego kodu jednej z tabel wyglądał następująco:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
CREATE  TABLE IF NOT EXISTS `meble`.`produkty` (
  `id` INT NOT NULL AUTO_INCREMENT ,
(...)
  `fabryka` INT NOT NULL ,
  PRIMARY KEY (`id`) ,
  INDEX `FK_Fabryki` (`fabryka` ASC) ,
(...)
  CONSTRAINT `FK_Fabryki`
    FOREIGN KEY (`fabryka` )
    REFERENCES `meble`.`fabryki` (`id` )
    ON DELETE NO ACTION
    ON UPDATE NO ACTION)
ENGINE = InnoDB

Gdzie jest błąd? Otóż, według manuala MySQL, nazwa ograniczenia musi być unikalna w skali całej bazy danych:

If the CONSTRAINT symbol clause is given, the symbol value must be unique in the database. If the clause is not given, InnoDB creates the name automatically.
A więc podczas tworzenia kodu należy wybrać jedną z dwóch możliwości: Informacja o tym była mi znana już wcześniej, problem w tym, że MySQL WorkBench nie zaprotestował przy próbie nazwania klucza obcego za pomocą istniejącego już identyfikatora. Cóż, człowiek się uczy całe życie, a szczególnie, kiedy przeoczy pewne oczywistości, tak jak ja w tym przypadku.