Koncepcje
Źle zrozumiałeś kilka podstawowych pojęć i wynikają z tego trudności. Najpierw musimy zająć się koncepcjami, a nie problemem, tak jak go postrzegasz, a w konsekwencji Twój problem zniknie.
automatycznie zwiększane identyfikatory, które są oczywiście kluczami podstawowymi.
Nie oni nie są. To powszechne nieporozumienie. I na pewno pojawią się problemy.
ID
pole nie może być kluczem podstawowym w sensie angielskim, technicznym lub relacyjnym.
-
Jasne, w SQL możesz zadeklarować dowolne pole, które ma być
PRIMARY KEY
, ale to nie przekształca go w magiczny sposób w klucz podstawowy w sensie angielskim, technicznym lub relacyjnym. Możesz nazwać chihuahua „Rottweiller”, ale to nie zmienia go w Rottweillera, pozostaje chihuahua. Jak każdy język, SQL po prostu wykonuje polecenia, które mu podajesz, nie rozumiePRIMARY KEY
aby oznaczać coś relacyjnego, po prostu uderza unikalny indeks w kolumnie (lub polu). -
Problem polega na tym, że zadeklarowałeś
ID
byćPRIMARY KEY
, myślisz go jako klucz podstawowy i możesz spodziewać się że ma pewne cechy Klucza Pierwotnego. Z wyjątkiem niepowtarzalności identyfikatora wartość , nie zapewnia żadnych korzyści. Nie ma żadnych cech Klucza Pierwotnego ani żadnego Klucza Relacyjnego. Nie jest to klucz w sensie angielskim, technicznym czy relacyjnym. Deklarując, że nieklucz jest kluczem, tylko pomylisz się i dowiesz się, że coś jest strasznie nie tak, tylko wtedy, gdy użytkownik narzeka na duplikaty w tabeli.
Tabele relacyjne muszą mieć wiersz wyjątkowość
PRIMARY KEY
na ID
pole nie zawiera wiersza wyjątkowość. Dlatego nie jest to tabela relacyjna zawierająca wiersze, a jeśli tak nie jest, to jest to plik zawierający rekordy. Nie ma żadnej integralności ani mocy (na tym etapie będziesz świadomy tylko mocy łączenia) ani szybkości, jaką ma tabela w relacyjnej bazie danych.
Wykonaj ten kod (MS SQL 2008) i udowodnij to sobie. Proszę, nie czytaj po prostu tego i nie rozumiej, a następnie przejdź do reszty tej odpowiedzi, ten kod musi zostać wykonany przed dalszym czytaniem . Ma wartość leczniczą.
CREATE TABLE dumb_file (
id INT NOT NULL IDENTITY PRIMARY KEY,
name_first CHAR(30) NOT NULL,
name_last CHAR(30) NOT NULL
)
INSERT dumb_file VALUES ( "Mickey", "Mouse" ) -- succeeds
INSERT dumb_file VALUES ( "Mickey", "Mouse" ) -- succeeds, but not intended
INSERT dumb_file VALUES ( "Mickey", "Mouse" ) -- succeeds, but not intended
SELECT * FROM dumb_file
Zauważ, że masz zduplikowane wiersze . Tabele relacyjne muszą mieć unikalne wiersze . Kolejny dowód na to, że nie masz tabeli relacyjnej ani żadnej z jej cech.
Zauważ, że w Twoim raporcie jedyną unikatową rzeczą jest ID
pole, na którym żaden użytkownik się nie przejmuje, żaden użytkownik nie widzi, bo to nie są dane, to jakieś dodatkowe bzdury, które jakiś bardzo głupi "nauczyciel" kazał ci wstawiać w każdym pliku. Masz rekord niepowtarzalność, ale nie wiersz wyjątkowość.
Jeśli chodzi o dane (prawdziwe dane bez dodatkowych dodatków), dane name_last
i name_first
może istnieć bez ID
pole. Osoba ma imię i nazwisko bez wybitego dowodu tożsamości na czole.
Drugą rzeczą, której używasz, a która Cię dezorientuje, jest AUTOINCREMENT.
Jeśli wdrażasz system archiwizacji rekordów bez funkcji relacyjnej, z pewnością jest to pomocne, nie musisz kodować przyrostu podczas wstawiania rekordów. Ale jeśli wdrażasz relacyjną bazę danych, nie ma to żadnego sensu, ponieważ nigdy jej nie użyjesz. W SQL jest wiele funkcji, których większość ludzi nigdy nie używa.
Działanie naprawcze
Jak więc uaktualnić, podnieść ten głupi_plik, który jest pełen zduplikowanych wierszy, do tabeli relacyjnej, aby uzyskać niektóre cechy i zalety tabeli relacyjnej? Są do tego trzy kroki.
-
Musisz zrozumieć klawisze
- A odkąd przeszliśmy od plików ISAM z lat 70. do Modelu relacyjnego , musisz zrozumieć klucze relacyjne . To znaczy, jeśli chcesz uzyskać korzyści (integralność, moc, szybkość) relacyjnej bazy danych.
Dr E F Cood, w swoim RM , oświadczył, że:
klucz składa się z danych
i
wiersze w tabeli muszą być niepowtarzalne
Twój „klucz” nie składa się z danych. Jest to jakiś dodatkowy, nie będący pasożytem danych, spowodowany przez twoje zarażenie chorobą twojego „nauczyciela”. Rozpoznaj to jako takie i pozwól sobie na pełną zdolność umysłową, którą dał ci Bóg (zauważ, że nie proszę cię o myślenie w kategoriach odosobnionych, fragmentarycznych lub abstrakcyjnych, wszystkie elementy w bazie danych muszą być ze sobą zintegrowane). Stwórz prawdziwy klucz z danych i tylko z danych. W tym przypadku jest tylko jeden możliwy klucz:
(name_last, name_first).
-
Wypróbuj ten kod , deklaruj unikalne ograniczenie danych:
CREATE TABLE dumb_table ( id INT NOT NULL IDENTITY PRIMARY KEY, name_first CHAR(30) NOT NULL, name_last CHAR(30) NOT NULL CONSTRAINT UK UNIQUE ( name_last, name_first ) ) INSERT dumb_table VALUES ( "Mickey", "Mouse" ) -- succeeds INSERT dumb_table VALUES ( "Mickey", "Mouse" ) -- fails, as intended INSERT dumb_table VALUES ( "Minnie", "Mouse" ) -- succeeds SELECT * FROM dumb_table
Teraz mamy unikalność wiersza . Taka jest sekwencja, która zdarza się większości ludzi:tworzą plik, który pozwala na duplikaty; nie mają pojęcia, dlaczego w listach rozwijanych pojawiają się duplikaty; użytkownik krzyczy; modyfikują plik i dodają indeks, aby zapobiec duplikatom; idą do następnej poprawki błędu. (Mogą to zrobić poprawnie lub nie, to już inna historia).
-
Drugi poziom. Dla myślących ludzi, którzy myślą poza naprawami. Skoro mamy teraz unikalność wierszy, to co w imię Nieba jest celem
ID
pole, dlaczego w ogóle go mamy ??? Och, bo chihuahua nazywa się Rotty i boimy się go dotknąć.Deklaracja, że jest to
PRIMARY KEY
jest fałszywe, ale pozostaje, powodując zamieszanie i fałszywe oczekiwania. Jedynym oryginalnym kluczem, jaki istnieje, jest(name_last, name_fist),
i jest to klucz alternatywny w tym momencie.Dlatego
ID
pole jest całkowicie zbędne; podobnie jak indeks, który to obsługuje; podobnie jak głupieAUTOINCREMENT
; podobnie jak fałszywa deklaracja, że jest toPRIMARY KEY
; a wszelkie oczekiwania co do tego są fałszywe.Dlatego usuń zbędne
ID
pole. Wypróbuj ten kod :CREATE TABLE honest_table ( name_first CHAR(30) NOT NULL, name_last CHAR(30) NOT NULL CONSTRAINT PK PRIMARY KEY ( name_last, name_first ) ) INSERT honest_table VALUES ( "Mickey", "Mouse" ) -- succeeds INSERT honest_table VALUES ( "Mickey", "Mouse" ) -- fails, as intended INSERT honest_table VALUES ( "Minnie", "Mouse" ) -- succeeds SELECT * FROM honest_table
Działa dobrze, działa zgodnie z przeznaczeniem, bez zbędnych pól i indeksów.
Pamiętaj o tym i rób to dobrze za każdym razem.
Fałszywi nauczyciele
Zgodnie z radą, w tych czasach ostatecznych będziemy mieć ich wielu. Zwróć uwagę na „nauczycieli”, którzy propagują ID
kolumny, dzięki szczegółowym dowodom w tym poście, po prostu nie rozumieją Modelu relacyjnego lub relacyjne bazy danych. Zwłaszcza ci, którzy piszą o tym książki.
Jak widać, utknęli w technologii ISAM sprzed 1970 roku. To wszystko, co rozumieją i to wszystko, czego mogą nauczyć. Używają kontenera bazy danych SQL, aby ułatwić dostęp, odzyskiwanie, tworzenie kopii zapasowych itp., ale zawartość jest czystym systemem archiwizacji rekordów bez integralności relacyjnej, mocy lub szybkości. AFAIC, to poważne oszustwo.
Oprócz ID
pola, oczywiście jest kilka pozycji, które są kluczowymi pojęciami Relacja-albo-nie, które razem wzięte powodują, że dochodzę do tak poważnego wniosku. Te inne elementy są poza zakresem tego posta.
Jedna szczególna para idiotów przeprowadza obecnie atak na Pierwszą Normalną Formę. Należą do azylu.
Odpowiedź
A teraz reszta Twojego pytania.
Czy istnieje sposób, aby utworzyć relacyjną tabelę bez utraty funkcji automatycznego przyrostu?
To jest zdanie wewnętrznie sprzeczne. Ufam, że zrozumiesz moje wyjaśnienie, tabele relacyjne nie są potrzebne dla AUTOINCREMENT
"funkcje"; jeśli plik ma AUTOINCREMENT
, nie jest to tabela relacyjna.
AUTOINCREMENT
jest dobre tylko z jednego powodu:jeśli i tylko wtedy, gdy chcesz utworzyć arkusz kalkulacyjny Excel w kontenerze bazy danych SQL, wypełniony polami o nazwie A,
B,
i C,
na górze i zapisz liczby po lewej stronie. W kategoriach bazy danych jest to wynik SELECT, spłaszczony widok danych, czyli nie źródło danych, które są zorganizowane (znormalizowane).
Innym możliwym (ale nie preferowanym) rozwiązaniem może być inny klucz podstawowy w pierwszej tabeli, który jest nazwą użytkownika, oczywiście nie z instrukcją automatycznego przyrostu. Czy to nieuniknione?
W pracy technicznej nie dbamy o preferencje, bo to jest subiektywne i cały czas się zmienia. Dbamy o poprawność techniczną, bo to jest obiektywne i to się nie zmienia.
Tak, to nieuniknione. Bo to tylko kwestia czasu; liczba błędów; liczba „nie mogę zrobić”; wielu użytkowników krzyczy, aż staniesz twarzą w twarz z faktami, pokonasz fałszywe deklaracje i zdasz sobie sprawę, że:
-
jedyny sposób, aby upewnić się, że użytkownik wiersze są unikalne, że nazwy użytkowników są unikalne, jest zadeklarowanie
UNIQUE
ograniczenie na nim -
i pozbądź się
user_id
lubid
w pliku użytkownika -
który promuje
user_name
naPRIMARY KEY
Tak, ponieważ cały twój problem z trzecim stołem, nieprzypadkowo, zostaje wyeliminowany.
Ta trzecia tabela to Tabela asocjacyjna . Jedyny wymagany klucz (klucz podstawowy) to połączenie dwóch nadrzędnych kluczy podstawowych. Zapewnia to niepowtarzalność wierszy , które są identyfikowane przez ich klucze, a nie przez ich IDs.
Ostrzegam Cię o tym, ponieważ ci sami „nauczyciele”, którzy nauczyli Cię błędu implementacji ID
pola, naucz błąd implementacji ID
pola w Tabeli Asocjacyjnej, gdzie podobnie jak w przypadku zwykłej tabeli jest ona zbędna, nie ma sensu, wprowadza duplikaty i powoduje zamieszanie. I jest to podwójnie zbędne, ponieważ dwa klucze, które zapewniają, już tam są, patrząc nam prosto w twarz.
Ponieważ nie rozumieją RM lub terminy relacyjne, nazywają tabele asocjacyjne tabelami „łącza” lub „map”. Jeśli mają ID
pola, w rzeczywistości są to pliki.
Tabele przeglądowe
ID
pola są szczególnie głupą rzeczą do zrobienia dla tabel przeglądowych lub referencyjnych. Większość z nich posiada rozpoznawalne kody, nie ma potrzeby wyliczania w nich listy kodów, ponieważ kody są (powinny być) niepowtarzalne.
Co więcej, posiadanie kodów w tabelach podrzędnych jako FKs, jest Dobrą Rzeczą:kod jest znacznie bardziej znaczący i często oszczędza niepotrzebne sprzężenie:
SELECT ...
FROM child_table -- not the lookup table
WHERE gender_code = "M" -- FK in the child, PK in the lookup
zamiast:
SELECT ...
FROM child_table
WHERE gender_id = 6 -- meaningless to the maintainer
lub gorzej:
SELECT ...
FROM child_table C -- that you are trying to determine
JOIN lookup_table L
ON C.gender_id = L.gender_id
WHERE L.gender_code = "M" -- meaningful, known
Pamiętaj, że jest to coś, czego nie można uniknąć:potrzebujesz niepowtarzalności kodu wyszukiwania i wyjątkowość w opisie. To jedyna metoda zapobiegania duplikatom w każdej z dwóch kolumn:
CREATE TABLE gender (
gender_code CHAR(2) NOT NULL,
name CHAR(30) NOT NULL
CONSTRAINT PK
PRIMARY KEY ( gender_code )
CONSTRAINT AK
UNIQUE ( name )
)
Pełny przykład
Na podstawie szczegółów w twoim pytaniu podejrzewam, że masz problemy ze składnią SQL i definicją FK, więc podam całe potrzebne rozwiązanie jako przykład (ponieważ nie podałeś definicji plików):
CREATE TABLE user ( -- Typical Identifying Table
user_name CHAR(16) NOT NULL, -- Short PK
name_first CHAR(30) NOT NULL, -- Alt Key.1
name_last CHAR(30) NOT NULL, -- Alt Key.2
birth_date DATE NOT NULL -- Alt Key.3
CONSTRAINT PK -- unique user_name
PRIMARY KEY ( user_name )
CONSTRAINT AK -- unique person identification
PRIMARY KEY ( name_last, name_first, birth_date )
)
CREATE TABLE sport ( -- Typical Lookup Table
sport_code CHAR(4) NOT NULL, -- PK Short code
name CHAR(30) NOT NULL -- AK
CONSTRAINT PK
PRIMARY KEY ( sport_code )
CONSTRAINT AK
PRIMARY KEY ( name )
)
CREATE TABLE user_sport ( -- Typical Associative Table
user_name CHAR(16) NOT NULL, -- PK.1, FK
sport_code CHAR(4) NOT NULL, -- PK.2, FK
start_date DATE NOT NULL
CONSTRAINT PK
PRIMARY KEY ( user_name, sport_code )
CONSTRAINT user_plays_sport_fk
FOREIGN KEY ( user_name )
REFERENCES user ( user_name )
CONSTRAINT sport_occupies_user_fk
FOREIGN KEY ( sport_code )
REFERENCES sport ( sport_code )
)
Tam PRIMARY KEY
deklaracja jest szczera, jest to klucz podstawowy; brak ID;
nie AUTOINCREMENT;
bez dodatkowych indeksów; brak zduplikowanych wierszy; brak błędnych oczekiwań; żadnych wynikających z tego problemów.
Model danych
Oto model danych z definicjami.
-
Jeśli nie jesteś przyzwyczajony do notacji, pamiętaj, że każdy mały tik, wycięcie i oznaczenie, linia ciągła vs przerywana, kwadrat vs zaokrąglone rogi, oznacza coś bardzo konkretnego. Zapoznaj się z Zapis IDEF1X .
-
Obraz jest wart tysiąca słów; w tym przypadku standardowe zdjęcie reklamacyjne jest warte więcej; zły nie jest wart papieru, na którym jest narysowany.
-
Proszę dokładnie sprawdzić frazy czasownikowe, stanowią one zestaw predykatów. Pozostałą część predykatów można określić bezpośrednio z modelu. Jeśli nie jest to jasne, zapytaj.