Koncept
Du har missuppfattat vissa grundläggande begrepp, och svårigheterna blir resultatet av det. Vi måste ta itu med begreppen först, inte problemet som du uppfattar det, och följaktligen kommer ditt problem att försvinna.
automatiskt inkrementerade ID, som naturligtvis är primärnycklar.
Nej det är de inte. Det är en vanlig missuppfattning. Och problem kommer garanterat att uppstå.
Ett ID
fältet kan inte vara en primär nyckel i engelska eller tekniska eller relationella betydelser.
-
Visst, i SQL kan du deklarera alla fältet ska vara en
PRIMARY KEY
, men det förvandlar den inte på magiskt sätt till en primärnyckel i engelska, tekniska eller relationella bemärkelser. Du kan döpa en chihuahua till "Rottweiller", men det förvandlar den inte till en rottweiller, den förblir en chihuahua. Som alla språk, kör SQL helt enkelt kommandona som du ger det, det förstår intePRIMARY KEY
för att betyda något Relationellt, slår det bara ett unikt index på kolumnen (eller fältet). -
Problemet är att du har deklarerat
ID
vara enPRIMARY KEY
, du tänker av den som en primärnyckel, och du kan förvänta dig att den har några av egenskaperna hos en Primärnyckel. Förutom det unika med ID-värdet värde , det ger ingen fördel. Den har ingen av egenskaperna hos en primärnyckel, eller någon form av relationsnyckel för den delen. Det är inte en nyckel i engelska, tekniska eller relationella betydelser. Genom att förklara att en icke-nyckel är en nyckel, kommer du bara att förvirra dig själv, och du kommer att upptäcka att det är något fruktansvärt fel först när användaren klagar på dubbletter i tabellen.
Relationstabeller måste ha rad unika
En PRIMARY KEY
på ett ID
fältet innehåller inte rad unikhet. Därför är det inte en relationstabell som innehåller rader, och om det inte är det är det en fil som innehåller poster. Den har inte någon av den integritet eller kraft (i detta skede kommer du bara att vara medveten om join-power) eller hastighet som en tabell i en relationsdatabas har.
Kör denna kod (MS SQL 2008) och bevisa det för dig själv. Vänligen läs inte bara detta och förstå det, och fortsätt sedan med att läsa resten av det här svaret, den här koden måste köras innan du läser vidare . Det har botande värde.
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
Lägg märke till att du har dubbletter av rader . Relationstabeller måste ha unika rader . Ytterligare bevis på att du inte har en relationstabell, eller någon av egenskaperna hos en.
Lägg märke till att i din rapport är det enda som är unikt ID
fältet, som ingen användare bryr sig om, ingen användare ser, eftersom det inte är data, det är något extra nonsens som någon väldigt dum "lärare" sa åt dig att lägga i varje fil. Du har rekord unikhet men inte rad unikhet.
När det gäller data (den verkliga datan minus de främmande tilläggen), data name_last
och name_first
kan existera utan ID
fält. En person har ett för- och efternamn utan att legitimation är stämplad i pannan.
Det andra du använder som förvirrar dig är AUTOINCREMENT.
Om du implementerar ett registerarkiveringssystem utan relationskapacitet är det säkert till hjälp, du behöver inte koda inkrementet när du infogar poster. Men om du implementerar en relationsdatabas tjänar den inget syfte alls, eftersom du aldrig kommer att använda den. Det finns många funktioner i SQL som de flesta aldrig använder.
Korrigerande åtgärd
Så hur uppgraderar, höjer du den dumb_filen som är full av dubbletter av rader till en relationstabell, för att få några av egenskaperna och fördelarna med en relationstabell? Det finns tre steg för detta.
-
Du måste förstå Keys
- Och sedan vi har gått från ISAM-filer från 1970-talet till Relationsmodellen måste du förstå Relationsnycklar . Det vill säga om du vill få fördelarna (integritet, kraft, hastighet) med en relationsdatabas.
Dr E F Cood, i hans RM , förklarade att:
en nyckel består av data
och
raderna i en tabell måste vara unika
Din "nyckel" består inte av data. Det är en ytterligare, icke-dataparasit, orsakad av att du är infekterad med din "lärares" sjukdom. Känn igen det som sådant och tillåt dig själv hela den mentala kapacitet som Gud gav dig (lägg märke till att jag inte ber dig att tänka i isolerade eller fragmenterade eller abstrakta termer, alla element i en databas måste integreras med varandra). Skapa en riktig nyckel av data, och endast från data. I det här fallet finns det bara en möjlig nyckel:
(name_last, name_first).
-
Prova den här koden , deklarera en unik begränsning av data:
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
Nu har vi radunikthet . Det är den sekvens som händer de flesta människor:de skapar en fil som tillåter duperingar; de har ingen aning om varför duper dyker upp i rullgardinsmenyn; användaren skriker; de finjusterar filen och lägger till ett index för att förhindra duper; de går till nästa buggfix. (De kan göra det korrekt eller inte, det är en annan historia.)
-
Den andra nivån. För tänkande människor som tänker bortom fix-its. Eftersom vi nu har unika rader, vad i himlens namn är syftet med
ID
fältet, varför har vi det ens ??? Åh, för att chihuahuan heter Rotty och vi är rädda för att röra vid den.Deklarationen att det är en
PRIMARY KEY
är falsk, men den förblir, vilket orsakar förvirring och falska förväntningar. Den enda äkta nyckeln som finns är(name_last, name_fist),
och det är en alternativ nyckel vid det här laget.Därför
ID
fältet är helt överflödigt; och så är indexet som stöder det; och så är den dummaAUTOINCREMENT
; och så är den falska deklarationen att det är enPRIMARY KEY
; och alla förväntningar du kan ha på det är falska.Ta därför bort det överflödiga
ID
fält. Prova den här koden :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
Fungerar bra, fungerar som det är tänkt, utan främmande fält och index.
Kom ihåg detta och gör det rätt, varje gång.
Falsklärare
I dessa yttersta tider kommer vi att ha många av dem. Observera väl, "lärarna" som sprider ID
kolumner, på grund av de detaljerade bevisen i detta inlägg, förstår helt enkelt inte Relationsmodellen eller relationsdatabaser. Speciellt de som skriver böcker om det.
Som visats har de fastnat i ISAM-tekniken före 1970. Det är allt de förstår, och det är allt de kan lära ut. De använder en SQL-databasbehållare för att underlätta åtkomst, återställning, säkerhetskopiering, etc, men innehållet är ett rent registerarkiveringssystem utan relationsintegritet, kraft eller hastighet. AFAIC, det är ett allvarligt bedrägeri.
Förutom ID
fält, naturligtvis, det finns flera saker som är viktiga Relationella-eller-ej-begrepp, som tillsammans får mig att dra en så allvarlig slutsats. Dessa andra föremål ligger utanför det här inläggets omfattning.
Ett särskilt par idioter utför för närvarande ett angrepp på First Normal Form. De hör hemma i asylet.
Svar
Nu till resten av din fråga.
Finns det något sätt jag kan skapa en relationstabell utan att förlora funktioner för automatisk ökning?
Det är en mening som motsäger sig själv. Jag litar på att du kommer att förstå av min förklaring, relationstabeller har inget behov för AUTOINCREMENT
"funktioner"; om filen har AUTOINCREMENT
, det är inte en relationstabell.
AUTOINCREMENT
är bra för bara en sak:om, och bara om, du vill skapa ett Excel-kalkylblad i SQL-databasbehållaren, fylld med fält med namnet A,
B,
och C,
längst upp och spela in siffror längst till vänster. I databastermer är det resultatet av en SELECT, en tillplattad vy av data, det vill säga inte källan av data, som är organiserad (normaliserad).
En annan möjlig (men inte föredragen) lösning kan vara att det finns en annan primärnyckel i den första tabellen, vilket är användarens användarnamn, inte med en automatisk inkrementsats, förstås. Är det oundvikligt?
I tekniskt arbete bryr vi oss inte om preferenser, eftersom det är subjektivt, och det förändras hela tiden. Vi bryr oss om teknisk korrekthet, eftersom det är objektivt, och det förändras inte.
Ja, det är oundvikligt. För det är bara en tidsfråga; antal buggar; antal "kan inte göra"; antal användarskrik, tills du inser fakta, övervinner dina falska deklarationer och inser att:
-
det enda sättet att säkerställa att användaren rader är unika, att användarnamn är unika, är att deklarera en
UNIQUE
begränsning på det -
och bli av med
user_id
ellerid
i användarfilen -
som främjar
user_name
tillPRIMARY KEY
Ja, eftersom hela ditt problem med det tredje bordet, inte av en slump, då elimineras.
Den tredje tabellen är en associativ tabell . Den enda nyckel som krävs (primärnyckel) är en sammansättning av de två överordnade primärnycklarna. Det säkerställer att raderna är unika , som identifieras av deras nycklar, inte av deras IDs.
Jag varnar dig för det eftersom samma "lärare" som lärde dig felet att implementera ID
fält, lär dig felet med att implementera ID
fält i den associativa tabellen, där den, precis som med en vanlig tabell, är överflödig, inte tjänar något syfte, introducerar dubbletter och orsakar förvirring. Och det är dubbelt överflödigt eftersom de två nycklarna som ger redan finns där och stirrar oss i ansiktet.
Eftersom de inte förstår RM , eller Relationella termer, kallar de associativa tabeller "länk" eller "karta"-tabeller. Om de har ett ID
fältet är de i själva verket filer.
Söktabeller
ID
fält är särskilt dum sak att göra för uppslags- eller referenstabeller. De flesta av dem har igenkännbara koder, det finns ingen anledning att räkna upp listan med koder i dem, eftersom koderna är (ska vara) unika.
Dessutom är det bra att ha koderna i de underordnade tabellerna som FK:er:koden är mycket mer meningsfull och den sparar ofta en onödig koppling:
SELECT ...
FROM child_table -- not the lookup table
WHERE gender_code = "M" -- FK in the child, PK in the lookup
istället för:
SELECT ...
FROM child_table
WHERE gender_id = 6 -- meaningless to the maintainer
eller ännu värre:
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
Observera att detta är något man inte kan undvika:du behöver unikhet på uppslagskoden och unika på beskrivningen. Det är den enda metoden för att förhindra dubbletter i varje av de två kolumnerna:
CREATE TABLE gender (
gender_code CHAR(2) NOT NULL,
name CHAR(30) NOT NULL
CONSTRAINT PK
PRIMARY KEY ( gender_code )
CONSTRAINT AK
UNIQUE ( name )
)
Fullständigt exempel
Från detaljerna i din fråga misstänker jag att du har SQL-syntax och FK-definitionsproblem, så jag kommer att ge hela lösningen du behöver som ett exempel (eftersom du inte har angett fildefinitioner):
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 )
)
Där, PRIMARY KEY
deklarationen är ärlig, den är en primärnyckel; inget ID;
ingen AUTOINCREMENT;
inga extra index; inga dubbletter av rader; inga felaktiga förväntningar; inga följdproblem.
Datamodell
Här är datamodellen för definitionerna.
-
Om du inte är van vid notationen, tänk på att varje liten bock, hack och markering, de heldragna vs streckade linjerna, de fyrkantiga vs runda hörnen, betyder något mycket specifikt. Se IDEF1X-notation .
-
En bild säger mer än tusen ord; i detta fall är en standard-klagomålsbild värd mer än så; en dålig är inte värd pappret den är ritad på.
-
Vänligen kontrollera verbfraserna noggrant, de består av en uppsättning predikat. Resten av predikaten kan bestämmas direkt från modellen. Fråga om detta inte är tydligt.