Convenzione di denominazione chiave primaria / chiave esterna [chiusa]


95

Nel nostro gruppo di sviluppo abbiamo un acceso dibattito sulla convenzione di denominazione per le chiavi primarie e straniere. Ci sono fondamentalmente due scuole di pensiero nel nostro gruppo:

1:

Primary Table (Employee)   
Primary Key is called ID

Foreign table (Event)  
Foreign key is called EmployeeID

o

2:

Primary Table (Employee)  
Primary Key is called EmployeeID

Foreign table (Event)  
Foreign key is called EmployeeID

Preferisco non duplicare il nome della tabella in nessuna delle colonne (quindi preferisco l'opzione 1 sopra). Concettualmente, è coerente con molte delle pratiche consigliate in altre lingue, in cui non si utilizza il nome dell'oggetto nei nomi delle proprietà. Penso che nominare la chiave esterna EmployeeID(o Employee_IDpotrebbe essere migliore) dica al lettore che è la IDcolonna della Employeetabella.

Alcuni altri preferiscono l'opzione 2 in cui si nomina la chiave primaria con il prefisso del nome della tabella in modo che il nome della colonna sia lo stesso in tutto il database. Capisco quel punto, ma ora non puoi distinguere visivamente una chiave primaria da una chiave esterna.

Inoltre, penso che sia ridondante avere il nome della tabella nel nome della colonna, perché se pensi alla tabella come un'entità e una colonna come una proprietà o un attributo di quell'entità, la pensi come l'attributo ID del Employee, non l' EmployeeIDattributo di un dipendente. Non vado a chiedere al mio collega che cosa sia PersonAgeo che PersonGendersia. Gli chiedo qual è la sua età.

Quindi, come ho detto, è un dibattito furioso e continuiamo all'infinito. Mi interessa avere nuove prospettive.



1
Ho letto più di 10 domande simili e finalmente ho trovato che le 3 migliori risposte qui sono buone: stackoverflow.com/a/465146/781695
utente

Solo una nota a margine: la scelta 2 ti consentirebbe di "Natural Join". Diamine, perché non farlo ancora nella scelta 1 aggiungendo "Employee.ID come EmployeeID". Ma il modo migliore per fare pratica sembra essere "Partecipa" utilizzando "ON Employee.ID = Event.EmployeeID".
Leone

In entrambe le situazioni dovrai usare alias (o 'table_name.column_name') in una o più code perché in entrambi i casi stai ripetendo i nomi delle colonne.
Please_Dont_Bully_Me_SO_Lords

Risposte:


52

Non importa davvero. Non mi sono mai imbattuto in un sistema in cui c'è una reale differenza tra la scelta 1 e la scelta 2.

Jeff Atwood ha pubblicato un ottimo articolo su questo argomento qualche tempo fa. Fondamentalmente le persone discutono e discutono più furiosamente quegli argomenti su cui non possono essere smentite. O da una prospettiva diversa, quegli argomenti che possono essere vinti solo attraverso argomenti ostili basati sulla resistenza.

Scegline uno e dì loro di concentrarsi sui problemi che hanno effettivamente un impatto sul tuo codice.

EDIT: Se vuoi divertirti, chiedi loro di specificare a lungo perché il loro metodo è superiore per i riferimenti di tabella ricorsivi.


26
+1, per il buon senso ... Ci sono cose più importanti su cui discutere .. Quindi, fallo a modo mio (scelta 2)
Charles Bretana

5
E, per autoreferenziare DRI, quando ci sono più di un FK che autoreferisce lo stesso PK, DEVI violare entrambi gli "standard", poiché le due colonne FK non possono essere denominate allo stesso modo ... ad esempio, EmployeeTable with EmployeeId PK, SupervisorId FK, MentorId Fk, PartnerId FK, ecc. ecc ...
Charles Bretana

75

Se le due colonne hanno lo stesso nome in entrambe le tabelle (convenzione n. 2), puoi utilizzare la sintassi USING in SQL per risparmiare un po 'di digitazione e un po' di rumore boilerplate:

SELECT name, address, amount
  FROM employees JOIN payroll USING (employee_id)

Un altro argomento a favore della convenzione n. 2 è che è il modo in cui è stato progettato il modello relazionale .

Il significato di ogni colonna è parzialmente trasmesso etichettandolo con il nome del dominio corrispondente.


4
La sintassi e la semantica SQL in realtà danno un buon indizio su come dovrebbe essere usata. ad esempio, la sintassi USING significa che le colonne con lo stesso dominio dovrebbero avere lo stesso nome, NULL = NULL -> NULL significa che NULL è "sconosciuto" anziché "non applicabile" e ON UPDATE CASCADE significa che le chiavi devono essere solo uniche, non immutabili.
Steven Huwig,

6
Ancora meglio, permette questo: SELECT name, address, amount FROM employees NATURAL JOIN payroll.
giorno del

5
Non userei il join naturale nel codice distribuito, perché è più fragile nel caso di aggiunte di schemi. Ma per le query interattive, è fantastico.
Steven Huwig

3
+1 ma c'è sempre un'eccezione. Ad esempio, se hai due colonne nel libro paga che sono entrambe chiavi esterne per il dipendente (un riferimento alla persona che viene pagato, la seconda al manager con autorità di bilancio, ad esempio). Ma non possiamo nominare entrambe le chiavi esterne employee_id.
Bill Karwin

1
La parola chiave "using" è specifica di MySql. Non funziona in T-SQL, sfortunatamente.
birdus

12

Penso che dipenda da come la tua applicazione è stata composta. Se utilizzi ORM o progetti le tue tabelle per rappresentare oggetti, l'opzione 1 potrebbe fare al caso tuo.

Mi piace codificare il database come un proprio livello. Controllo tutto e l'app chiama solo stored procedure. È bello avere set di risultati con nomi di colonna completi, specialmente quando ci sono molte tabelle unite e molte colonne restituite. Con questo tipo di applicazione, mi piace l'opzione 2. Mi piace molto vedere la corrispondenza dei nomi delle colonne sui join. Ho lavorato su vecchi sistemi in cui non corrispondevano ed è stato un incubo,


4
+1 per aver individuato join con nomi di colonna non corrispondenti
Raj More

4
sui "vecchi sistemi" l'handicap di nomi lunghi 8 caratteri che fa molto più male di questo. Sono disposto ad uscire su un arto e ipotizzare che avere il PK denominato ID non fosse la causa principale dell'incubo nei vecchi sistemi con cui avevi a che fare. Inoltre "risucchiava nei vecchi sistemi" è usato troppo spesso nello sviluppo di software, specialmente nei database. Vedo regolarmente persone che giustificano una determinata pratica A, in base al modo in cui ha funzionato nella loro esperienza su un sistema DB rilasciato 10+ anni fa.
Russell Steen

2
le applicazioni allo stato dell'arte di oggi saranno una vecchia schifezza in pochi anni. potresti persino riscrivere l'interfaccia o utilizzare i dati in un'altra piattaforma, ma i tuoi dati (inclusi i nomi delle colonne) dovranno resistere alla prova del tempo.
KM.

2
Quindi le persone 20 anni fa avrebbero dovuto in qualche modo usare nomi di colonne che avevano un senso oggi, anche se avevano solo 8 caratteri? I formati di archiviazione dei dati sono cambiati drasticamente negli ultimi 20 anni e cambieranno di nuovo nei prossimi 20. Non c'è modo di dimostrare che la tua preferenza resisterà alla prova del tempo meglio dell'altro metodo elencato. "I nomi delle colonne" potrebbero essere essi stessi "vecchie schifezze" quando le persone avranno questa discussione tra 20 anni, poiché la nostra capacità di memorizzare e manipolare i dati migliora. Le tabelle sono un costrutto umano che rappresenta imperfettamente le relazioni di dati ...
Russell Steen,

1
Grazie per la risposta intellettuale ben motivata.
Russell Steen

3

Nessuna delle due convenzioni funziona in tutti i casi, quindi perché averne una? Usa il senso comune...

ad esempio, per la tabella autoreferenziale, quando ci sono più di una colonna FK che auto-referenzia il PK della stessa tabella, DEVI violare entrambi gli "standard", poiché le due colonne FK non possono avere lo stesso nome ... es. , EmployeeTable con EmployeeId PK, SupervisorId FK, MentorId Fk, PartnerId FK, ...


1
+1 per la risposta effettiva dell'obiettivo tecnico
DVK

Una buona risposta applicabile, ma gli argomenti alla risposta di Dems non centrano il punto.
JYelton

3

Sono d'accordo che c'è poco da scegliere tra di loro. Per me una cosa molto più significativa di entrambi gli standard è la parte "standard".

Se le persone iniziano a "fare le proprie cose", dovrebbero essere impiccate. A PARER MIO :)


3
+1 per riconoscere che la coerenza è più importante dell'essere "giusti" (in questo caso)
Russell Steen

-1 per aver tentato di applicare una "sciocca coerenza". Un vecchio proverbio cinese dice: "Una sciocca coerenza è un folletto per menti semplici".
Charles Bretana

@charles: in un mondo in cui persone diverse mantengono il codice l'una dell'altra, spesso quando l'autore se ne è andato e la documentazione è obsoleta o inesistente, questa non è una coerenza sciocca. Sono così felice di non lavorare con te ...
MatBailie

@Dems, senza offesa, ma è sciocco, per due motivi. 1) Ci sono scenari comuni e chiaramente comprensibili in cui QUALSIASI standard dovrebbe essere violato. (vedi la mia risposta per esempi e 2) perché su questo tema, almeno, uno standard aggiungerebbe pochissimo valore, tranne per far sentire più a suo agio le persone a cui piacciono gli standard ...
Charles Bretana

1
si potrebbe sostenere che "ID" è più coerente, perché non appena si introduce la lingua inglese "carID" nella tabella "cars" o nella tabella "car"? "sheepID" nella tabella "sheep" o "sheeps" - le cose iniziano a diventare incoerenti. Se ti attieni a "ID" e nomi di tabelle singolari - questo non è solo coerente è funziona bene con molti ORM / richiede anche meno configurazione (ad esempio Dapper Contrib)
niico

3

Hai considerato quanto segue?

Primary Table (Employee)   
Primary Key is PK_Employee

Foreign table (Event)  
Foreign key is called FK_Employee

3
Non sopporto quando le persone votano e non mi spiegano il motivo. Questa è una risposta completamente valida, che sia appetibile o meno per alcuni è una domanda diversa, ma è soggettiva e non richiede un voto negativo.
Jeremy

1
Grazie per averlo fatto notare. Sarei anche interessato ai motivi per cui non useresti questo formato. E sono abbastanza sicuro che ci saranno buone ragioni ...
Wouter

Questa è la migliore via d'uscita in quanto non dovrai usarla table_name.column_namenelle query e non dovrai usare alias per i nomi delle colonne se non hai nomi ripetuti ...
Please_Dont_Bully_Me_SO_Lords

1
Questa potrebbe essere considerata una forma di notazione ungherese. Quindi considera gli argomenti a favore e contro quello.
Fred

2

La convenzione che usiamo dove lavoro è molto simile alla A, con l'eccezione che nominiamo le tabelle nella forma plurale (cioè "impiegati") e usiamo trattini bassi tra il nome della tabella e quello della colonna. Il vantaggio è che per fare riferimento a una colonna, è "dipendenti _ id" o "dipendenti.id", a seconda di come si desidera accedervi. Se è necessario specificare da quale tabella proviene la colonna, "dipendenti.employees _ id" è decisamente ridondante.


Non ho deciso se mi piacciono i nomi di tabella pluralizzati. Usando il singolare, le query sembrano leggere meglio ("dipendente.name" in contrapposizione a "dipendenti.name"). Anche nei join sembra leggere meglio poiché stai unendo singoli record a un'altra tabella. Ma i nomi di tabella pluralizzati sembrano più accurati quando si pensa alla tabella, piuttosto che alla query. Mi atterrò al singolare perché è quello che usiamo, ma penso che sia anche la strada giusta da percorrere (anche se di nuovo, molti non sono d'accordo)
MatBailie

Si. È più una preferenza personale e / o qualunque cosa tu sia abituato a vedere, immagino.
Jarett Millard

2

Se stai guardando il codice dell'applicazione, non solo le query del database, alcune cose mi sembrano chiare:

  1. Le definizioni di tabella di solito si associano direttamente a una classe che descrive un oggetto, quindi dovrebbero essere singolari. Per descrivere una raccolta di un oggetto, di solito aggiungo "Array" o "List" o "Collection" al nome singolare, poiché più chiaramente dell'uso dei plurali indica non solo che si tratta di una raccolta, ma che tipo di raccolta è. In quella vista, vedo il nome di una tabella non come il nome della raccolta, ma il nome del tipo di oggetto di cui è una raccolta. Un DBA che non scrive il codice dell'applicazione potrebbe perdere questo punto.

  2. I dati che trattano spesso utilizzano "ID" per scopi di identificazione non chiave. Per eliminare la confusione tra "ID" chiave e "ID" non chiave, per il nome della chiave primaria, utilizziamo "Chiave" (è quello che è, non è vero?) Preceduto dal nome della tabella o da un'abbreviazione di il nome della tabella. Questo prefisso (e lo riservo solo per la chiave primaria) rende il nome della chiave univoco, il che è particolarmente importante perché usiamo nomi di variabili che sono gli stessi dei nomi delle colonne del database e la maggior parte delle classi ha un genitore, identificato dal nome di la chiave genitore. Anche questo è necessario per assicurarsi che non sia una parola chiave riservata, come la sola "Chiave". Per facilitare il mantenimento della coerenza dei nomi delle variabili chiave e per fornire programmi che eseguono join naturali, le chiavi esterne hanno lo stesso nome utilizzato nella tabella in cui sono la chiave primaria. Ho incontrato più di una volta programmi che funzionano molto meglio in questo modo utilizzando i join naturali. Su quest'ultimo punto ammetto un problema con le tabelle autoreferenziali, che ho utilizzato. In questo caso, farei un'eccezione alla regola di denominazione delle chiavi esterne. Ad esempio, utilizzerei ManagerKey come chiave esterna nella tabella Employee per puntare a un altro record in quella tabella.


Molti mapper relazionali a oggetti (ORM) come Entity Framework consentono di mappare una tabella a una classe con un nome diverso. Ciò consente di avere una classe denominata "Utente" e una tabella denominata "Utenti".
Fred

2

Mi piace la convenzione n. 2: nella ricerca di questo argomento e nel trovare questa domanda prima di pubblicare la mia, mi sono imbattuto nel problema in cui:

Sto selezionando * da una tabella con un numero elevato di colonne e unendola a una seconda tabella che allo stesso modo ha un numero elevato di colonne. Entrambe le tabelle hanno una colonna "id" come chiave primaria, e ciò significa che devo selezionare specificamente ogni colonna (per quanto ne so) per rendere questi due valori univoci nel risultato, ovvero:

SELECT table1.id AS parent_id, table2.id AS child_id

Sebbene l'uso della convenzione n. 2 significhi che avrò ancora alcune colonne nel risultato con lo stesso nome, ora posso specificare di quale ID ho bisogno (genitore o figlio) e, come suggerito da Steven Huwig, l' USINGistruzione semplifica ulteriormente le cose.


2
SELECT *è un no-no per (la maggior parte) delle query di produzione, comunque, quindi non è una buona ragione per scegliere uno standard di denominazione.
P Daddy

1
Non sono in disaccordo: potresti fornire un collegamento a un motivo per cui è così? Non mi piace l'idea di dover mantenere i nomi di 80 colonne nella mia query.
JYelton

Al momento non è possibile trovare un collegamento (difficile da cercare su Google per "*"), ma illustrerò i punti fondamentali: (1) le modifiche alle tabelle possono avere un impatto negativo sulla tua applicazione, (2) può essere un male per le prestazioni e (3) specificare esplicitamente quali dati sono effettivamente necessari può rendere il codice più facile da capire. Questi punti potrebbero espandersi e ci sono delle eccezioni (come ho accennato) ma qui non è appropriato. Se pubblichi questa come una nuova domanda, io (e altri) saremo lieti di elaborare ulteriormente.
P Daddy

2
Lo posso fare. Mi rendo conto del vantaggio in termini di prestazioni, ma devo considerare l'investimento di tempo durante la modifica del codice. Sono sempre alla ricerca di modi per migliorare l'interazione tra l'app e il database. Grazie.
JYelton

1
Non sono così sicuro che SELECT *sia un no-no per la maggior parte delle query di produzione. Se aumenta notevolmente la velocità di sviluppo e rende il codice molto più conciso e leggibile, consentendoti di concentrarti su questioni più importanti, perché no SELECT *? Dipende molto dalle circostanze di ciascuna situazione ed è un compromesso tra molti fattori. Una regola raramente si adatta a tutto.
niico

2

Ho sempre usato userId come PK su una tabella e userId su un'altra tabella come FK. Sto seriamente pensando di utilizzare userIdPK e userIdFK come nomi per identificare l'uno dall'altro. Mi aiuterà a identificare PK e FK rapidamente quando guardo le tabelle e sembra che chiarirà il codice quando si utilizza PHP / SQL per accedere ai dati rendendolo più facile da capire. Soprattutto quando qualcun altro guarda il mio codice.


1

Uso la convenzione n. 2. Ora sto lavorando con un modello di dati legacy in cui non so cosa significhi in una determinata tabella. Dov'è il male nell'essere verboso?


1

Che ne dici di nominare la chiave esterna

role_id

dove ruolo è il ruolo che l'entità di riferimento ha rispetto al tavolo a portata di mano. Questo risolve il problema del riferimento ricorsivo e di più fks sulla stessa tabella.

In molti casi sarà identico al nome della tabella di riferimento. In questo caso diventa identico a una delle vostre proposte.

In ogni caso avere lunghe discussioni è una cattiva idea


0

"Where in" Employee INNER JOIN order ON order.employee_id = Employee.id "è necessaria una qualifica aggiuntiva?".

Non c'è bisogno di qualifiche aggiuntive perché la qualifica di cui ho parlato è già lì.

"il motivo per cui un utente aziendale fa riferimento all'ID ordine o all'ID dipendente è per fornire il contesto, ma a livello di base hai già il contesto perché ti riferisci alla tabella".

Per favore, dimmi, se la colonna si chiama "ID", allora come viene eseguita esattamente quella "referenza [sic] al tavolo", a meno che non qualifichi questo riferimento alla colonna ID esattamente nel modo in cui ho parlato?

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.