Perché le persone consigliano di non utilizzare il nome "Id" per una colonna di identità?


68

Mi è stato insegnato a non usare il nome Idper la colonna identità delle mie tabelle, ma ultimamente lo sto usando comunque perché è semplice, breve e molto descrittivo su cosa siano effettivamente i dati.

Ho visto persone suggerire il prefisso Idcon il nome della tabella, ma questo sembra solo rendere più lavoro per la persona che scrive le query SQL (o il programmatore se stai usando un ORM come Entity Framework), in particolare su nomi di tabelle più lunghi come CustomerProductIdoAgencyGroupAssignementId

Un fornitore di terze parti che abbiamo assunto per creare qualcosa per noi in realtà ha chiamato tutte le loro colonne di identità Identsolo per evitare di utilizzarlo Id. All'inizio ho pensato che lo facessero perché Idera una parola chiave, ma quando l'ho esaminato, ho scoperto che Idnon è una parola chiave in SQL Server 2005, che è quello che stiamo usando.

Quindi perché le persone raccomandano di non usare il nome Idper una colonna di identità?

Modifica: per chiarire, non sto chiedendo quale convenzione di denominazione utilizzare, o perché gli argomenti utilizzino una convenzione di denominazione sull'altra. Voglio solo sapere perché si consiglia di non utilizzare Idper il nome della colonna identità.

Sono un singolo programmatore, non un dba, e per me il database è solo un posto dove archiviare i miei dati. Poiché di solito creo piccole app e in genere utilizzo un ORM per l'accesso ai dati, è molto più facile lavorare con un nome di campo comune per il campo di identità. Voglio sapere cosa mi sto perdendo facendo questo, e se ci sono davvero dei buoni motivi per non farlo.


10
BF bunfight qui già: programmers.stackexchange.com/q/114728/5905 Molti di noi (leggi: io) sono stati risucchiati ...
gbn,

Esiste davvero una regola del genere contro l'uso di "id" come nome della colonna identità? ActiveRecord, l'ORM standard per Ruby on Rails, fa esattamente questo per convenzione. ar.rubyonrails.org
200_success

1
@ 200_success A livello di database, sì. Questo è il sito del database, non il sito ORM;)
JNK

2
Inoltre, in particolare per SQL Server, vedere dba.stackexchange.com/questions/124655/… e, più specificamente, connect.microsoft.com/SQLServer/feedback/details/2178150
Aaron Bertrand

Risposte:


46

Il prefisso del nome della tabella ha ottime ragioni.

Tener conto di:

TableA (id int identity, stringdata varchar(max))

TableB (id int identity, stringdata varchar(max))

Vogliamo DELETEdai TableArecord che esistono in entrambe le tabelle. Abbastanza facile, faremo solo un INNER JOIN:

DELETE a
FROM 
  TableA A
INNER JOIN 
  TableB B
    ON b.id = B.id

.... e abbiamo appena spazzato via tutto TableA. Abbiamo inavvertitamente confrontato l'ID di B con se stesso: ogni record ha trovato corrispondenza e ogni record è stato eliminato.

Se i campi fossero stati nominati TableAIde TableBIdquesto sarebbe impossibile ( Invalid field name TableAid in TableB).

Personalmente non ho alcun problema con l'uso del nome idin una tabella, ma è davvero una buona prassi prefigurarlo con il nome della tabella (o il nome dell'entità, se le TableApersone PeopleIdfunzionassero anche bene) per evitare il confronto accidentale con il campo sbagliato e la soffiatura c'è qualcosa.

Ciò rende anche molto ovvio da dove provengono i campi in lunghe query con molti messaggi JOIN.


10
Quindi è fondamentalmente una convenzione di denominazione per proteggere dagli errori? Penserei di usare begin transactione commit transactionsarebbe una pratica migliore che usare (imo) uno schema di denominazione più odioso
Rachel

13
@Rachel: è per 1. chiarezza 2. evitare alias di colonna non necessari 3. consentire JOIN..USING 4. infastidire le scimmie PHP che lavorano in singoli oggetti, non in set
gbn

4
@Rachel Se non hai notato l'errore durante la scrittura della query, e poco prima di eseguirla, è improbabile che te ne accorga prima di impegnarti. Queste cose accadono, perché renderle più probabili?
Andy,

7
@Andy Faccio sempre uno SELECTper trovare i miei record prima di eseguire il DELETE, e una volta eseguito l'istruzione, controllo sempre che il conteggio delle righe sia quello che mi aspetto prima di eseguire il commit.
Rachel,

5
@ Rachel È bello che tu abbia qualcosa che funzioni per te. Puoi farlo fare a tutti?
Andy,

36

Principalmente serve a evitare che le chiavi esterne diventino un dolore tremendo. Supponiamo che tu abbia due tabelle: Customer e CustomerAddress. La chiave primaria per entrambi è una colonna denominata id, che è una colonna identità (int).

Ora devi avere l'ID cliente referenziato da CustomerAddress. Non puoi nominare l'id della colonna, ovviamente, quindi vai con customer_id.

Questo porta a un paio di problemi. Innanzitutto, devi sempre ricordare quando chiamare la colonna "id" e quando chiamarla "customer_id". E se sbagli questo, porta al secondo problema. Se hai una query di grandi dimensioni con una dozzina di join e non restituisce alcun dato, divertiti a giocare a Where's Waldo e a dare la caccia a questo errore di battitura:

ON c.id = ca.id

Whoops, avrebbe dovuto essere ON c.id = ca.customer_id. O meglio ancora, dai un nome descrittivo alle colonne della tua identità, in modo che possa essere ON c.customer_id = ca.customer_id. Quindi, se accidentalmente usi l'alias di tabella errato da qualche parte, customer_id non sarà una colonna in quella tabella e otterrai un buon errore di compilazione, piuttosto che risultati vuoti e successivo squinting del codice.

Certo, ci sono casi in cui questo non aiuta, ad esempio se hai bisogno di più relazioni di chiave esterna da una tabella a un'altra singola tabella, ma la denominazione di tutte le chiavi primarie "id" non aiuta neanche lì.


27

Ecco un riepilogo di tutte le risposte sui vantaggi ottenuti dalla convenzione per non utilizzare un nome comune per tutte le chiavi primarie:

  • Meno errori, poiché i campi identità non hanno lo stesso nome

    Non è possibile scrivere erroneamente una query su cui si unisce B.Id = B.Idinvece di A.Id = B.Id, perché i campi identità non verranno mai identificati con lo stesso nome.

  • Nomi di colonna più chiari.

    Se guardi una colonna denominata CustomerId, sai immediatamente quali sono i dati in quella colonna. Se il nome della colonna era qualcosa di generico Id, allora devi conoscere anche il nome della tabella per sapere quali dati contiene la colonna.

  • Evita gli alias di colonna non necessari

    A questo punto è possibile scrivere SELECT CustomerId, ProductIdda una query che unisce Customerscon Products, al posto diSELECT Customer.Id as CustomerId, Products.Id as ProductId

  • Permette la JOIN..USINGsintassi

    È possibile unire le tabelle con la sintassi Customer JOIN Products USING (CustomerId), anzichéCustomer JOIN Products ON Customer.Id = Products.Id

  • La chiave è più facile da trovare nelle ricerche

    Se stai cercando il campo di identità di un cliente in una soluzione di grandi dimensioni, la ricerca CustomerIdè molto più utile della ricercaId

Se riesci a pensare ad altri vantaggi di questa convenzione di denominazione, fammi sapere e lo aggiungerò all'elenco.

Che tu scelga di utilizzare nomi di colonna univoci o identici per i campi di identità dipende da te, ma indipendentemente da ciò che scegli, si prega di essere coerenti :)


12

Per copiare la mia risposta dalla domanda collegata:

C'è una situazione in cui attaccare "ID" su ogni tabella non è la migliore idea: la USINGparola chiave, se è supportata. Lo usiamo spesso in MySQL.

Ad esempio, se hai fooTablecon colonna fooTableIde barTablecon chiave esterna fooTableId, le tue query possono essere costruite come tali:

SELECT fooTableId, fooField1, barField2 FROM fooTable INNER JOIN barTable USING (fooTableId)

Non solo salva la digitazione, ma è molto più leggibile rispetto all'alternativa:

SELECT fooTable.Id, fooField1, barField2 FROM fooTable INNER JOIN barTable ON (fooTable.Id = barTable.foTableId)

9

Dopo aver normalizzato uno schema di database per limitare la ridondanza, le tabelle vengono divise in tabelle più piccole con relazioni stabilite (da uno a uno, da uno a molti, da molti a molti). Nel processo singoli campi nella tabella originale possono apparire in più tabelle normalizzate.

Ad esempio, un database per un blog potrebbe apparire così nella sua forma non normalizzata, assumendo un vincolo univoco sul nome autore.

| Author_Nickname | Author_Email | Post_Title | Post_Body |
+-----------------+--------------+------------+-----------+
| dave            | dave@x.com   | Blah       | Bla bla   |
| dave            | dave@x.com   | Stuff      | I like    |
| sophie          | s@oph.ie     | Lorem      | Ipsum     |

La normalizzazione produrrebbe due tabelle:

Autore:

| Author_Nickname | Author_Email |
+-----------------+--------------+
| dave            | dave@x.com   |
| sophie          | s@oph.ie     |

Inviare

| Author_Nickname | Post_Title | Post_Body |
+-----------------+------------+-----------+
| dave            | Blah       | Bla bla   |
| dave            | Stuff      | I like    |
| sophie          | Lorem      | Ipsum     |

Qui Author_Nickname sarebbe una chiave primaria per la tabella degli autori e una chiave esterna nella tabella delle poste. Anche se Author_Nickname appare in due tabelle, corrisponde comunque a una singola unità di informazioni, ad es. il nome di ogni colonna corrisponde a un singolo campo .

In molti casi non può esserci un vincolo univoco sui campi originali, quindi un campo artificiale numerico viene utilizzato come chiave primaria. Ciò non cambia il fatto che il nome di ogni colonna rappresenti ancora un singolo campo. Nella progettazione tradizionale del database, i nomi delle singole colonne corrispondono a singoli campi anche se non sono chiavi. (ad esempio, si userebbero part.partname e client.clientname anziché part.name e client.name ). Questa è la ragione dell'esistenza delle INNER JOIN ... USING <key>e delle NATURAL JOINsintassi.

Tuttavia, al giorno d'oggi, e con i livelli ORM prontamente disponibili in molte lingue, i database sono spesso progettati come livello di persistenza per i linguaggi OO, in cui è naturale che le variabili che hanno lo stesso ruolo in classi diverse siano chiamate uguali ( nome parte e client.name , non part.partname e client.clientname ). In tale contesto, tendo a utilizzare "ID" per le mie chiavi primarie.


7

Un fornitore di terze parti che abbiamo assunto per creare qualcosa per noi in realtà ha chiamato tutte le colonne Ident per identificarlo solo per evitare di usare Id.

L'uso di "Ident" anziché "Id" non risolve davvero nulla se "Ident" finisce per essere utilizzato su tutte le loro tabelle.

C'è un buon articolo sulle convenzioni di codifica SQL sul sito Drupal che indica una buona pratica per questa situazione:

È buona norma aggiungere un prefisso ai nomi delle tabelle con il nome del modulo per evitare possibili conflitti nello spazio dei nomi.

Da questo punto di vista, CustomerProductId e AgencyGroupAssignmentId hanno senso usare. Sì, è abbastanza dettagliato. Potresti accorciarlo, ma il punto più importante di cui preoccuparti è se lo sviluppatore che ti segue capirà o meno cosa intendi . Gli ID preceduti da nomi di tabelle dettagliati non devono lasciare ambiguità su cosa siano. E (per me) questo è più importante del salvataggio di alcuni tasti.


7

Nomino le mie colonne CustomerID anziché ID, quindi ogni volta che scrivo

FROM dbo.Customers AS c JOIN dbo.CustomerOrders AS o

Il prompt SQL suggerisce immediatamente quanto segue

ON c.CustomerID = o.CustomerID 

Mi fa risparmiare alcuni tasti. Eppure penso che le convenzioni di denominazione siano molto soggettive e come tali non ho una forte opinione in un modo o nell'altro.


5

È la stessa ragione per cui non dovresti nominare tutti i tuoi campi varchar come "UserText" e "UserText1", o perché non dovresti usare "UserDate" e "UserDate1".

In genere se si dispone di un campo identità in una tabella, è la chiave primaria. Come costruiresti una tabella figlio con una chiave esterna in una tabella padre se la chiave primaria in entrambe le tabelle fosse id?

Non tutti sono d'accordo con questo metodo, ma nei miei database assegno un'abbreviazione unica a ogni tabella. Il PK per quella tabella sarebbe stato chiamato PK_ [abbrv] ID. Se viene usato come FK ovunque, allora userei l'ID FK_ [abbrv]. Ora ho zero ipotesi di lavoro per capire quali sono le relazioni tra tabelle.


5

Fondamentalmente per lo stesso motivo in genere non si denominano i parametri parametro1, parametro2 ... è accurato, ma non descrittivo. Se vedi TableId, probabilmente puoi tranquillamente supporre che sia usato per contenere un pk per Table, indipendentemente dal contesto.

Per quanto riguarda chiunque abbia usato Ident, non ha capito il punto, data la scelta tra Ident e Id use Id. Ident è ancora più confuso di Id.

Fuori dal contesto, si può presumere che Id sia la chiave primaria di alcune tabelle (non estremamente utile a meno che l'id non sia una guida), ma Ident non lo dice nemmeno (o almeno io). Alla fine avrei capito che Ident è l'abbreviazione di identità (in un modo o nell'altro), ma il tempo che ho trascorso a capire che sarebbe stato sprecato.


3

Utilizzare un prefisso in modo che sia possibile utilizzare lo stesso nome in entrambi i contesti di chiave primaria e chiave esterna, in modo da poter eseguire natural join/ join ... using.

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.