Concetti
Hai frainteso alcuni concetti di base e le difficoltà ne derivano. Dobbiamo prima affrontare i concetti, non il problema come lo percepisci e, di conseguenza, il tuo problema scomparirà.
ID a incremento automatico, che ovviamente sono chiavi primarie.
No non lo sono. Questo è un malinteso comune. E i problemi sono garantiti.
Un ID
campo non può essere una chiave primaria in senso inglese o tecnico o relazionale.
-
Certo, in SQL puoi dichiarare qualsiasi deve essere un
PRIMARY KEY
, ma questo non la trasforma magicamente in una Chiave Primaria nel senso inglese, tecnico o relazionale. Puoi chiamare un chihuahua "Rottweiller", ma questo non lo trasforma in un Rottweiller, rimane un chihuahua. Come ogni linguaggio, SQL esegue semplicemente i comandi che gli dai, non comprendePRIMARY KEY
per significare qualcosa di relazionale, colpisce semplicemente un indice univoco sulla colonna (o campo). -
Il problema è che hai dichiarato il
ID
essere unaPRIMARY KEY
, tu pensi come chiave primaria e potresti aspettarti che ha alcune delle qualità di una Chiave Primaria. Fatta eccezione per l'univocità dell'ID valore , non fornisce alcun vantaggio. Non ha nessuna delle qualità di una Chiave Primaria, o qualsiasi tipo di Chiave Relazionale per quella materia. Non è una chiave nel senso inglese, tecnico o relazionale. Dichiarando una chiave non chiave, ti confonderai solo e scoprirai che c'è qualcosa di terribilmente sbagliato solo quando l'utente si lamenta dei duplicati nella tabella.
Le tabelle relazionali devono avere riga unicità
Una PRIMARY KEY
su un ID
il campo non fornisce riga unicità. Pertanto non è una tabella relazionale contenente righe e, in caso contrario, è un file contenente record. Non ha alcuna integrità o potenza (in questa fase sarai a conoscenza solo della potenza di unione) o velocità di una tabella in un database relazionale.
Esegui questo codice (MS SQL 2008) e dimostralo a te stesso. Per favore, non leggere semplicemente questo e capirlo, quindi procedi a leggere il resto di questa risposta, questo codice deve essere eseguito prima di leggere ulteriormente . Ha valore curativo.
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
Nota che hai righe duplicate . Le tabelle relazionali devono avere righe univoche . Un'ulteriore prova che non hai una tabella relazionale, o nessuna delle sue qualità.
Nota che nel tuo rapporto l'unica cosa che è univoca è l'ID
campo, di cui nessun utente si preoccupa, nessun utente vede, perché non sono dati, è un'ulteriore sciocchezza che qualche "insegnante" molto stupido ti ha detto di inserire in ogni file. Hai record unicità ma non riga unicità.
In termini di dati (i dati reali meno le aggiunte estranee), i dati name_last
e name_first
può esistere senza il ID
campo. Una persona ha un nome e un cognome senza un documento d'identità stampigliato sulla fronte.
La seconda cosa che stai usando che ti confonde è AUTOINCREMENT.
Se stai implementando un sistema di archiviazione di record senza capacità relazionali, sicuramente è utile, non devi codificare l'incremento durante l'inserimento dei record. Ma se stai implementando un database relazionale, non serve a nulla, perché non lo utilizzerai mai. Ci sono molte funzionalità in SQL che la maggior parte delle persone non usa mai.
Azione correttiva
Quindi, come si aggiorna, eleva, quel file dumb che è pieno di righe duplicate in una tabella relazionale, al fine di ottenere alcune delle qualità e dei vantaggi di una tabella relazionale? Ci sono tre passaggi per farlo.
-
Devi capire le chiavi
- E da quando siamo passati dai file ISAM degli anni '70 al Modello Relazionale , devi comprendere le Chiavi relazionali . Ovvero se desideri ottenere i benefici (integrità, potenza, velocità) di un Database Relazionale.
Dr EF Cood, nel suo RM , ha dichiarato che:
una chiave è composta dai dati
e
le righe di una tabella devono essere univoche
La tua "chiave" non è composta dai dati. È un parassita aggiuntivo, non dati, causato dal fatto che sei stato infettato dalla malattia del tuo "insegnante". Riconoscilo come tale, e concediti la piena capacità mentale che Dio ti ha dato (nota che non ti chiedo di pensare in termini isolati o frammentati o astratti, tutti gli elementi di un database devono essere integrati tra loro). Crea una vera chiave dai dati e solo dai dati. In questo caso, c'è solo una chiave possibile:
(name_last, name_first).
-
Prova questo codice , dichiara un vincolo univoco sui dati:
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
Ora abbiamo unicità di riga . Questa è la sequenza che succede alla maggior parte delle persone:creano un file che consente i duplicati; non hanno idea del motivo per cui i duplicati appaiono nei menu a discesa; l'utente urla; modificano il file e aggiungono un indice per evitare duplicati; vanno alla prossima correzione del bug. (Potrebbero farlo correttamente o meno, questa è un'altra storia.)
-
Il secondo livello. Per le persone pensanti che pensano oltre le correzioni. Dato che ora abbiamo l'unicità della riga, quello che in nome del Cielo è lo scopo del
ID
campo, perché ce l'abbiamo anche noi??? Oh, perché il chihuahua si chiama Rotty e abbiamo paura di toccarlo.La dichiarazione che si tratta di una
PRIMARY KEY
è falso, ma rimane, provocando confusione e false aspettative. L'unica chiave autentica che c'è è il(name_last, name_fist),
ed è una Chiave alternativa a questo punto.Pertanto il
ID
il campo è del tutto superfluo; e così è l'indice che lo supporta; e così è lo stupidoAUTOINCREMENT
; e così è la falsa dichiarazione che si tratta di unaPRIMARY KEY
; e tutte le aspettative che potresti avere su di esso sono false.Rimuovere quindi il superfluo
ID
campo. Prova questo codice :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
Funziona bene, funziona come previsto, senza campi e indici estranei.
Per favore, ricordalo e fallo bene, ogni singola volta.
Falsi insegnanti
In questi ultimi tempi, come consigliato, ne avremo molti. Nota bene, gli "insegnanti" che propagano ID
colonne, in virtù dell'evidenza dettagliata in questo post, semplicemente non comprendono il Modello relazionale o Database relazionali. Soprattutto quelli che ne scrivono libri.
Come evidenziato, sono bloccati nella tecnologia ISAM precedente al 1970. Questo è tutto ciò che capiscono, ed è tutto ciò che possono insegnare. Usano un contenitore di database SQL, per facilitare l'accesso, il ripristino, il backup, ecc., ma il contenuto è puro sistema di archiviazione dei record senza integrità relazionale, potenza o velocità. AFAIC, è una grave frode.
Oltre a ID
campi, ovviamente, ci sono diversi elementi che sono concetti chiave Relazionale o no, che presi insieme, mi portano a trarre una conclusione così grave. Questi altri elementi esulano dallo scopo di questo post.
Una coppia in particolare di idioti sta attualmente organizzando un assalto alla Prima Forma Normale. Appartengono al manicomio.
Risposta
Ora per il resto della tua domanda.
C'è un modo per creare una tabella relazionale senza perdere le funzioni di incremento automatico?
Questa è una frase contraddittoria. Confido che capirai dalla mia spiegazione, le tabelle relazionali non ne hanno bisogno per AUTOINCREMENT
"caratteristiche"; se il file ha AUTOINCREMENT
, non è una tabella relazionale.
AUTOINCREMENT
va bene solo per una cosa:se, e solo se, vuoi creare un foglio di calcolo Excel nel contenitore del database SQL, riempilo con i campi chiamati A,
B,
e C,
in alto e registra i numeri in basso a sinistra. In termini di database, questo è il risultato di un SELECT, una vista appiattita dei dati, cioè non la fonte di dati, che è organizzato (normalizzato).
Un'altra soluzione possibile (ma non preferita) potrebbe essere la presenza di un'altra chiave primaria nella prima tabella, che è il nome utente dell'utente, ovviamente non con un'istruzione di incremento automatico. È inevitabile?
Nel lavoro tecnico non ci interessano le preferenze, perché sono soggettive e cambiano continuamente. Abbiamo a cuore la correttezza tecnica, perché è oggettiva e non cambia.
Sì, è inevitabile. Perché è solo questione di tempo; numero di bug; numero di "non posso fare"; numero di utenti urla, finché non affronti i fatti, superi le tue false dichiarazioni e ti rendi conto che:
-
l'unico modo per garantire che l'utente riga sono univoci, che i nomi_utente sono univoci, significa dichiarare un
UNIQUE
vincolo su di esso -
e sbarazzati di
user_id
oid
nel file utente -
che promuove
user_name
aPRIMARY KEY
Sì, perché tutto il tuo problema con il terzo tavolo, non a caso, viene poi eliminato.
Quel terzo tavolo è un Tavolo associativo . L'unica chiave richiesta (Chiave primaria) è un composto delle due chiavi primarie principali. Ciò garantisce l'unicità delle righe , che sono identificati dalle loro chiavi, non dai loro IDs.
Te ne sto avvisando perché gli stessi "insegnanti" che ti hanno insegnato l'errore di implementare ID
campi, insegna l'errore di implementazione di ID
campi della tabella associativa, dove, proprio come con una tabella ordinaria, è superflua, non serve a nulla, introduce duplicati e crea confusione. Ed è doppiamente superfluo perché le due chiavi che forniscono sono già lì, a fissarci in faccia.
Dal momento che non capiscono il RM , o termini relazionali, chiamano tabelle "collegamento" o "mappa" delle tabelle associative. Se hanno un ID
campo, sono infatti dei file.
Tabelle di ricerca
ID
i campi sono particolarmente Cosa stupida da fare per tabelle di ricerca o di riferimento. La maggior parte di essi ha codici riconoscibili, non è necessario enumerare l'elenco dei codici in essi contenuti, perché i codici sono (dovrebbero essere) univoci.
Inoltre, avere i codici nelle tabelle figlie come FK, è una buona cosa:il codice è molto più significativo e spesso salva un join non necessario:
SELECT ...
FROM child_table -- not the lookup table
WHERE gender_code = "M" -- FK in the child, PK in the lookup
invece di:
SELECT ...
FROM child_table
WHERE gender_id = 6 -- meaningless to the maintainer
o peggio:
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
Nota che questo è qualcosa che non si può evitare:è necessaria l'unicità nel codice di ricerca e unicità nella descrizione. Questo è l'unico metodo per prevenire duplicati in ciascuno delle due colonne:
CREATE TABLE gender (
gender_code CHAR(2) NOT NULL,
name CHAR(30) NOT NULL
CONSTRAINT PK
PRIMARY KEY ( gender_code )
CONSTRAINT AK
UNIQUE ( name )
)
Esempio completo
Dai dettagli nella tua domanda, sospetto che tu abbia problemi di sintassi SQL e definizione FK, quindi fornirò l'intera soluzione di cui hai bisogno come esempio (poiché non hai fornito definizioni di file):
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 )
)
Lì, la PRIMARY KEY
la dichiarazione è onesta, è una Chiave Primaria; nessun ID;
no AUTOINCREMENT;
nessun indici extra; nessuna riga duplicata; nessuna aspettativa errata; nessun problema consequenziale.
Modello di dati
Ecco il modello di dati per andare con le definizioni.
-
Se non sei abituato alla notazione, tieni presente che ogni piccolo segno di spunta, tacca e segno, le linee continue e tratteggiate, gli angoli quadrati e arrotondati, significano qualcosa di molto specifico. Fare riferimento a IDEF1X Notation .
-
Un'immagine vale più di mille parole; in questo caso un'immagine standard di denuncia vale di più; uno cattivo non vale la carta su cui è disegnato.
-
Si prega di controllare attentamente le frasi verbali, esse comprendono una serie di predicati. Il resto dei predicati può essere determinato direttamente dal modello. Se questo non è chiaro, chiedi.