Concepten
Je hebt een aantal basisconcepten verkeerd begrepen en de moeilijkheden zijn daaruit voortgekomen. We moeten eerst de concepten aanpakken, niet het probleem zoals u het waarneemt, en bijgevolg zal uw probleem verdwijnen.
automatisch oplopende ID's, die natuurlijk primaire sleutels zijn.
Nee, dat zijn ze niet. Dat is een veel voorkomende misvatting. En er ontstaan gegarandeerd problemen.
Een ID
veld kan geen primaire sleutel zijn in de Engelse of technische of relationele zin.
-
Natuurlijk, in SQL kun je elke . declareren veld om een
PRIMARY KEY
te zijn , maar dat verandert het niet op magische wijze in een primaire sleutel in de Engelse, technische of relationele zin. Je kunt een chihuahua "Rottweiller" noemen, maar dat verandert hem niet in een Rottweiller, het blijft een chihuahua. Zoals elke taal voert SQL gewoon de commando's uit die je het geeft, het begrijptPRIMARY KEY
niet om iets relationeels te betekenen, slaat het gewoon een unieke index op de kolom (of veld). -
Het probleem is, aangezien u verklaard de
ID
eenPRIMARY KEY
zijn , jij denkt ervan als een primaire sleutel, en u kunt verwachten dat het enkele eigenschappen van een primaire sleutel heeft. Behalve de uniciteit van de ID waarde , levert het geen voordeel op. Het heeft geen van de kwaliteiten van een primaire sleutel, of wat voor soort relationele sleutel dan ook. Het is geen sleutel in de Engelse, technische of relationele zin. Door een niet-sleutel als een sleutel te verklaren, breng je jezelf alleen maar in verwarring en kom je er pas achter dat er iets vreselijk mis is als de gebruiker klaagt over duplicaten in de tabel.
Relationele tabellen moeten rij . hebben uniciteit
EEN PRIMARY KEY
op een ID
veld geeft geen rij uniciteit. Daarom is het geen relationele tabel die rijen bevat, en als dat niet het geval is, dan is het een bestand met records. Het heeft niet de integriteit, of kracht (in dit stadium zul je je alleen bewust zijn van de kracht van joins), of snelheid, die een tabel in een relationele database heeft.
Voer deze code uit (MS SQL 2008) en bewijs het aan jezelf. Lees dit alstublieft niet gewoon en begrijp het, en ga dan verder met het lezen van de rest van dit antwoord, deze code moet worden uitgevoerd voordat u verder leest . Het heeft genezende waarde.
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
Merk op dat u dubbele rijen heeft . Relationele tabellen moeten unieke rijen hebben . Verder bewijs dat je geen relationele tabel hebt, of een van de kwaliteiten ervan.
Merk op dat in uw rapport het enige dat uniek is de ID
. is veld, waar geen enkele gebruiker iets om geeft, geen gebruiker ziet, omdat het geen gegevens zijn, het is wat extra onzin die een of andere stomme "leraar" je vertelde om in elk bestand te zetten. Je hebt een record uniciteit maar niet rij uniciteit.
In termen van de gegevens (de echte gegevens minus de externe toevoegingen), de gegevens name_last
en name_first
kan bestaan zonder de ID
veld. Een persoon heeft een voornaam en achternaam zonder dat er een identiteitsbewijs op zijn voorhoofd is gestempeld.
Het tweede dat u gebruikt dat u in verwarring brengt, is de AUTOINCREMENT.
Als u een archiveringssysteem voor records implementeert zonder relationele mogelijkheden, is het natuurlijk handig dat u de increment niet hoeft te coderen bij het invoegen van records. Maar als u een relationele database implementeert, heeft het helemaal geen zin, omdat u het nooit zult gebruiken. Er zijn veel functies in SQL die de meeste mensen nooit gebruiken.
Corrigerende actie
Dus hoe upgrade, verhoog je dat dumb_file dat vol staat met dubbele rijen naar een relationele tabel, om enkele van de kwaliteiten en voordelen van een relationele tabel te krijgen? Hiervoor zijn drie stappen nodig.
-
U moet sleutels begrijpen
- En sinds we zijn overgegaan van ISAM-bestanden uit de jaren 70 naar het Relationele Model , moet u Relationele sleutels . begrijpen . Tenminste, als u gebruik wilt maken van de voordelen (integriteit, kracht, snelheid) van een relationele database.
Dr. E F Cood, in zijn RM , verklaarde dat:
een sleutel is samengesteld uit de gegevens
en
de rijen in een tabel moeten uniek zijn
Uw "sleutel" bestaat niet uit de gegevens. Het is een extra, niet-gegevensparasiet, veroorzaakt door uw besmetting met de ziekte van uw "leraar". Herken het als zodanig, en gun jezelf de volledige mentale capaciteit die God je heeft gegeven (merk op dat ik je niet vraag om in geïsoleerde of gefragmenteerde of abstracte termen te denken, alle elementen in een database moeten met elkaar geïntegreerd zijn). Verzin een echte sleutel van de gegevens, en alleen uit de gegevens. In dit geval is er maar één mogelijke Sleutel:
(name_last, name_first).
-
Probeer deze code , verklaren een unieke beperking op de gegevens:
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 hebben we uniekheid van rijen . Dat is de volgorde die de meeste mensen overkomt:ze maken een bestand aan dat dupes toestaat; ze hebben geen idee waarom dupes in de vervolgkeuzelijsten verschijnen; de gebruiker schreeuwt; ze tweaken het bestand en voegen een index toe om dupes te voorkomen; ze gaan naar de volgende bugfix. (Misschien doen ze dit correct of niet, dat is een ander verhaal.)
-
Het tweede niveau. Voor denkende mensen die verder denken dan de fix-its. Aangezien we nu rij-uniekheid hebben, wat is in hemelsnaam het doel van de
ID
veld, waarom hebben we het zelfs ??? Oh, want de chihuahua heet Rotty en we zijn bang om hem aan te raken.De verklaring dat het een
PRIMARY KEY
. is is vals, maar het blijft en veroorzaakt verwarring en valse verwachtingen. De enige echte sleutel die er is, is de(name_last, name_fist),
en het is een Alternatieve Sleutel op dit punt.Daarom de
ID
veld is totaal overbodig; en dat geldt ook voor de index die het ondersteunt; en dat geldt ook voor de stommeAUTOINCREMENT
; en dat geldt ook voor de valse verklaring dat het eenPRIMARY KEY
. is; en alle verwachtingen die u ervan heeft, zijn onjuist.Verwijder daarom de overbodige
ID
veld. Probeer deze code :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
Werkt prima, werkt zoals bedoeld, zonder de vreemde velden en indices.
Onthoud dit alstublieft en doe het elke keer goed.
Valse leraren
In deze eindtijd zullen we er, zoals geadviseerd, velen hebben. Let goed op, de "leraren" die ID
. propageren kolommen, op grond van het gedetailleerde bewijs in dit bericht, het relationele model gewoon niet begrijpen of relationele databases. Vooral degenen die er boeken over schrijven.
Zoals blijkt, zitten ze vast in de ISAM-technologie van vóór 1970. Dat is alles wat ze begrijpen, en dat is alles wat ze kunnen onderwijzen. Ze gebruiken een SQL-databasecontainer, voor het gemak van toegang, herstel, back-up, enz., maar de inhoud is puur Record Filing System zonder relationele integriteit, kracht of snelheid. AFAIC, het is een ernstige fraude.
Naast ID
velden, natuurlijk zijn er verschillende items die belangrijke relationele-of-niet-concepten zijn, die bij elkaar genomen ertoe leiden dat ik zo'n ernstige conclusie trek. Die andere items vallen buiten het bestek van dit bericht.
Een bepaald stel idioten voert momenteel een aanval uit op First Normal Form. Ze horen thuis in het gesticht.
Antwoord
Nu voor de rest van uw vraag.
Is er een manier waarop ik een relationele tabel kan maken zonder de functies voor automatisch verhogen te verliezen?
Dat is een zichzelf tegensprekende zin. Ik vertrouw erop dat u uit mijn uitleg zult begrijpen dat relationele tabellen niet nodig zijn voor AUTOINCREMENT
"Kenmerken"; als het bestand AUTOINCREMENT
. heeft , het is geen relationele tabel.
AUTOINCREMENT
is maar voor één ding goed:als, en alleen als, u een Excel-spreadsheet wilt maken in de SQL-databasecontainer, vol met velden met de naam A,
B,
en C,
over de bovenkant en noteer de nummers aan de linkerkant. In databasetermen is dat het resultaat van een SELECT, een afgeplatte weergave van de gegevens, dat is niet de bron van gegevens, die is georganiseerd (genormaliseerd).
Een andere mogelijke (maar niet geprefereerde) oplossing kan zijn dat er een andere primaire sleutel in de eerste tabel is, en dat is de gebruikersnaam van de gebruiker, natuurlijk niet met een auto-increment-statement. Is het onvermijdelijk?
In technisch werk geven we niet om voorkeuren, omdat dat subjectief is en voortdurend verandert. We geven om technische correctheid, want dat is objectief en verandert niet.
Ja, het is onvermijdelijk. Omdat het slechts een kwestie van tijd is; aantal fouten; aantal "kan niet"; aantal geschreeuw van gebruikers, totdat je de feiten onder ogen ziet, je valse verklaringen overwint en je realiseert dat:
-
de enige manier om ervoor te zorgen dat de gebruiker rijen uniek zijn, dat user_names uniek zijn, is om een
UNIQUE
te declareren beperking ervan -
en verwijder
user_id
ofid
in het gebruikersbestand -
die
user_name
promoot naarPRIMARY KEY
Ja, want je hele probleem met de derde tafel is dan, niet toevallig, verholpen.
Die derde tabel is een Associatieve tabel . De enige vereiste sleutel (primaire sleutel) is een samenstelling van de twee bovenliggende primaire sleutels. Dat zorgt voor uniekheid van de rijen , die worden geïdentificeerd door hun sleutels, niet door hun IDs.
Ik waarschuw je daarvoor omdat dezelfde "leraren" je de fout hebben geleerd om ID
te implementeren velden, leer de fout van het implementeren van ID
velden in de associatieve tabel, waar deze, net als bij een gewone tabel, overbodig is, geen zin heeft, duplicaten introduceert en verwarring veroorzaakt. En het is dubbel overbodig omdat de twee sleutels die ervoor zorgen er al zijn en ons in het gezicht staren.
Omdat ze de RM . niet begrijpen , of relationele termen, noemen ze associatieve tabellen "link" of "map" tabellen. Als ze een ID
. hebben veld, het zijn in feite bestanden.
Opzoektabellen
ID
velden zijn bijzonder Stom ding om te doen voor opzoek- of referentietabellen. De meeste hebben herkenbare codes, het is niet nodig om de lijst met codes daarin op te sommen, omdat de codes uniek zijn (zouden moeten zijn).
Verder is het een goede zaak om de codes in de onderliggende tabellen als FK's te hebben:de code is veel zinvoller en bespaart vaak een onnodige join:
SELECT ...
FROM child_table -- not the lookup table
WHERE gender_code = "M" -- FK in the child, PK in the lookup
in plaats van:
SELECT ...
FROM child_table
WHERE gender_id = 6 -- meaningless to the maintainer
of erger:
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
Merk op dat dit iets is dat je niet kunt vermijden:je hebt uniekheid nodig in de opzoekcode en uniciteit op de beschrijving. Dat is de enige methode om duplicaten in elke te voorkomen van de twee kolommen:
CREATE TABLE gender (
gender_code CHAR(2) NOT NULL,
name CHAR(30) NOT NULL
CONSTRAINT PK
PRIMARY KEY ( gender_code )
CONSTRAINT AK
UNIQUE ( name )
)
Volledig voorbeeld
Uit de details in je vraag vermoed ik dat je problemen hebt met de SQL-syntaxis en FK-definitie, dus ik zal de volledige oplossing die je nodig hebt als voorbeeld geven (aangezien je geen bestandsdefinities hebt gegeven):
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 )
)
Daar, de PRIMARY KEY
verklaring is eerlijk, het is een primaire sleutel; geen ID;
nee AUTOINCREMENT;
geen extra indexen; geen dubbele rijen; geen verkeerde verwachtingen; geen gevolgproblemen.
Gegevensmodel
Hier is het gegevensmodel dat bij de definities past.
-
Als u niet gewend bent aan de notatie, houd er dan rekening mee dat elk klein vinkje, inkeping en merkteken, de ononderbroken versus onderbroken lijnen, de vierkante versus ronde hoeken, iets heel specifieks betekent. Raadpleeg de IDEF1X-notatie .
-
Een foto zegt meer dan duizend woorden; in dit geval is een standaard klachtfoto meer waard; een slechte is het papier niet waard waarop het is getekend.
-
Controleer de werkwoordzinnen zorgvuldig, ze bestaan uit een reeks predikaten. De rest van de Predikaten kan direct uit het model worden bepaald. Als dit niet duidelijk is, vraag het dan.