Poprawnie wskazana składnia polecenia `ALTER TABLE Uczniowie ADD CONSTRAINT FKKlasy FOREIGN KEY(Klasy_id) REFERENCES Klasy(id);` dokładnie odpowiada temu, co chcemy osiągnąć: dodać ograniczenie klucza obcego do już istniejącej tabeli. W SQL (np. w standardowym podejściu stosowanym w SQL Server, Oracle, wielu innych systemach) dodawanie klucza obcego odbywa się właśnie przez `ALTER TABLE ... ADD CONSTRAINT ... FOREIGN KEY ... REFERENCES ...`. Najpierw wskazujemy modyfikowaną tabelę (`Uczniowie`), potem nazwę nowego ograniczenia (`FKKlasy`), następnie kolumnę w tabeli podrzędnej (`Klasy_id`), a na końcu tabelę oraz kolumnę, do której się odwołujemy (`Klasy(id)`). Dzięki temu silnik bazy danych wie, że każda wartość w `Uczniowie.Klasy_id` musi mieć odpowiadający rekord w `Klasy.id`. To jest właśnie istota referencyjnej integralności danych. W praktyce takie powiązanie uniemożliwia np. dopisanie ucznia do nieistniejącej klasy albo usunięcie klasy, do której nadal przypisani są uczniowie (chyba że jawnie zdefiniujemy `ON DELETE CASCADE` czy inne zachowanie). Moim zdaniem warto też zwracać uwagę na nazewnictwo: prefiks `FK` w nazwie ograniczenia (`FKKlasy`) to dobra praktyka, bo od razu widać, że to klucz obcy, a nie np. unikalny indeks. W większych projektach przyjęcie spójnej konwencji, typu `FK_Uczniowie_Klasy`, bardzo ułatwia debugowanie błędów i analizę schematu. W codziennej pracy z bazami danych takie polecenie wykorzystuje się często po wczytaniu danych testowych albo po przebudowie tabel, gdy chcemy najpierw stworzyć strukturę bez ograniczeń, a potem krok po kroku dokładać klucze główne i obce. Warto też pamiętać, że przed dodaniem klucza obcego kolumna `Klasy_id` powinna mieć ten sam lub kompatybilny typ co `Klasy.id` (np. oba `INT`) i nie może zawierać wartości, które nie istnieją w tabeli `Klasy`, bo wtedy polecenie zakończy się błędem i klucz obcy nie zostanie utworzony.
W poleceniach dotyczących kluczy obcych bardzo łatwo pomylić operacje `ADD` i `DROP` oraz prawidłową składnię dla poszczególnych dialektów SQL. W przedstawionych błędnych odpowiedziach pojawia się kilka typowych nieporozumień. Część z nich próbuje używać słowa kluczowego `DROP`, które służy do usuwania istniejącego ograniczenia, a nie do jego tworzenia. Jeżeli naszym celem jest dopiero dodanie relacji między tabelą `Uczniowie` a tabelą `Klasy`, to użycie `DROP CONSTRAINT` albo `DROP FOREIGN KEY` jest po prostu logicznie sprzeczne z zadaniem – takie polecenia mogłyby mieć sens tylko wtedy, gdy klucz obcy `FKKlasy` już istnieje i chcemy go zlikwidować. W praktyce takie pomyłki wynikają z mylenia dwóch kroków: projektowania schematu (gdzie klucze dopiero dodajemy) z refaktoryzacją istniejącej bazy (gdzie często coś usuwamy i tworzymy na nowo). Kolejna sprawa to składnia `ADD FOREIGN KEY FKKlasy FOREIGN KEY(...)`. W standardowych systemach zarządzania bazą danych najpierw podaje się `ADD CONSTRAINT nazwa`, a dopiero później słowo `FOREIGN KEY` wraz z listą kolumn. Wpychanie nazwy ograniczenia między `ADD FOREIGN KEY` a definicję kolumn nie jest zgodne z zasadami składni SQL i po prostu nie zadziała. Moim zdaniem to efekt mieszania różnych przykładów z internetu, gdzie w jednych pokazuje się nazwane ograniczenia (`ADD CONSTRAINT ...`), a w innych anonimowe (`ADD FOREIGN KEY (...) REFERENCES ...`), bez nazwy. Dodatkowo, używanie w jednym poleceniu jednocześnie `DROP` i całej definicji `FOREIGN KEY(Klasy_id) REFERENCES Klasy(id)` jest nielogiczne: przy usuwaniu ograniczenia podajemy wyłącznie jego nazwę, bo silnik bazy już zna szczegóły definicji i nie trzeba ich powtarzać. W poprawnym podejściu zawsze zadajemy sobie pytanie: czy ja chcę coś dodać, czy usunąć, i czy składnia, której używam, odpowiada dokumentacji konkretnego systemu (np. SQL Server, MySQL, PostgreSQL). Stosowanie czytelnej, udokumentowanej formy `ALTER TABLE ... ADD CONSTRAINT ... FOREIGN KEY ... REFERENCES ...` jest zgodne z dobrymi praktykami i oszczędza sporo nerwów przy późniejszej administracji oraz migracjach schematu.