Pourquoi les gens recommandent-ils de ne pas utiliser le nom «Id» pour une colonne d'identité?

68

On m'a appris à ne pas utiliser le nom Idde la colonne identité de mes tableaux, mais dernièrement, je viens de l'utiliser, car il est simple, bref et très descriptif sur la nature des données.

J'ai vu des personnes suggérer de préfixer Idle nom de la table, mais cela semble faire plus de travail pour la personne qui écrit les requêtes SQL (ou le programmeur si vous utilisez un ORM comme Entity Framework), en particulier pour les noms de table plus longs tels que CustomerProductIdouAgencyGroupAssignementId

Un fournisseur tiers que nous avons embauché pour créer quelque chose pour nous a en fait nommé toutes ses colonnes d’identité Identpour éviter de les utiliser Id. Au début, je pensais qu'ils l'avaient fait parce que Idc'était un mot clé, mais lorsque j'ai examiné cela, j'ai constaté que ce Idn'était pas un mot clé dans SQL Server 2005, et c'est ce que nous utilisons.

Alors, pourquoi les gens recommandent-ils de ne pas utiliser le nom Idd'une colonne d'identité?

Edit: Pour clarifier, je ne demande pas quelle convention de nommage utiliser, ni d'arguments pour utiliser une convention de nommage par rapport à l'autre. Je veux juste savoir pourquoi il est recommandé de ne pas utiliser Idle nom de la colonne d'identité.

Je suis un programmeur unique, pas un dba, et pour moi la base de données est juste un endroit pour stocker mes données. Étant donné que je crée généralement de petites applications et que j'utilise généralement un ORM pour l'accès aux données, il est beaucoup plus facile d'utiliser un nom de champ commun pour le champ d'identité. Je veux savoir ce qui me manque en faisant cela, et s'il y a vraiment de bonnes raisons pour que je ne le fasse pas.

Rachel
la source
10
BF bunfight ici déjà: programmers.stackexchange.com/q/114728/5905 Plusieurs d'entre nous (lire: moi) ont été aspirés ...
gbn
Existe-t-il vraiment une telle règle contre l'utilisation de "id" comme nom de la colonne d'identité? ActiveRecord, l'ORM standard pour Ruby on Rails, fait exactement cela par convention. ar.rubyonrails.org
200_success
1
@ 200_success Au niveau de la base de données, oui. C'est le site de base de données, pas le site ORM;)
JNK
2
En outre, pour plus de détails sur SQL Server, voir dba.stackexchange.com/questions/124655/… et, plus précisément, connect.microsoft.com/SQLServer/feedback/details/2178150
Aaron Bertrand

Réponses:

46

Le préfixe du nom de la table a de très bonnes raisons.

Considérer:

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

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

Nous voulons DELETEdes TableAenregistrements qui existent dans les deux tables. Assez facile, nous allons simplement faire un INNER JOIN:

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

et nous avons tout éliminé TableA. Nous avons par inadvertance comparé l'ID de B à lui-même - chaque enregistrement correspondant et chaque enregistrement étant supprimé.

Si les champs avaient été nommés TableAIdet que TableBIdcela serait impossible ( Invalid field name TableAid in TableB).

Personnellement, je n’ai aucun problème à utiliser le nom iddans une table, mais c’est vraiment une meilleure pratique de la préfacer avec le nom de la table (ou le nom de l’entité, si les TableAgens PeopleIdfonctionnent bien aussi) pour éviter de se comparer accidentellement au mauvais champ et de s’éjecter. quelque chose en place.

Cela rend également très évident la provenance des champs dans les longues requêtes avec beaucoup de JOINs.

JNK
la source
10
Il s’agit donc essentiellement d’une convention de dénomination visant à protéger contre les erreurs? Je pense que l’utilisation begin transactionet commit transactionla meilleure pratique que l’utilisation (imo) d’un système de nommage plus odieux
Rachel
13
@Rachel: c'est pour 1. la clarté 2. éviter les alias de colonnes inutiles 3. permettre à JOIN..USING 4. gêner les singes PHP qui travaillent dans des objets simples et non dans des ensembles
gbn
4
@Rachel Si vous n'avez pas remarqué l'erreur lors de l'écriture de la requête et juste avant de l'exécuter, il est peu probable que vous la remarquiez avant de commettre. Ce truc arrive, pourquoi le rendre plus probable?
Andy
7
@Andy, je fais toujours SELECTpour rechercher mes enregistrements avant de l'exécuter DELETE, et une fois que j'ai exécuté l'instruction, je vérifie toujours que le nombre de lignes correspond à ce que j'attendais avant de valider.
Rachel
5
@ Rachel C'est bien que vous ayez quelque chose qui fonctionne pour vous. Pouvez-vous faire que tout le monde fasse ça?
Andy
36

C'est principalement pour empêcher les clés étrangères de devenir une douleur énorme. Supposons que vous ayez deux tables: Customer et CustomerAddress. La clé primaire pour les deux est une colonne nommée id, qui est une colonne d'identité (int).

Vous devez maintenant avoir l'ID client référencé à partir de CustomerAddress. Vous ne pouvez évidemment pas nommer l'id de la colonne, vous devez donc utiliser customer_id.

Cela soulève quelques problèmes. Tout d'abord, vous devez vous rappeler systématiquement quand appeler la colonne "id" et quand l'appeler "customer_id". Et si vous vous trompez, cela conduit au deuxième problème. Si vous avez une requête volumineuse avec une douzaine de jointures et qu'elle ne renvoie aucune donnée, amusez-vous à jouer à Where's Waldo et à traquer cette faute de frappe:

ON c.id = ca.id

Oups, aurait dû être ON c.id = ca.customer_id. Ou mieux encore, nommez vos colonnes d’identité de manière descriptive, pour qu’elles le soient ON c.customer_id = ca.customer_id. Ensuite, si vous utilisez accidentellement le mauvais alias de table quelque part, customer_id ne sera pas une colonne de cette table et vous obtiendrez une belle erreur de compilation plutôt que des résultats vides et un plissement de code ultérieur.

Certes, dans certains cas, cela n’aide pas, par exemple si vous avez besoin de plusieurs relations de clé étrangère d’une table à l’autre, mais le nom de toutes les clés primaires "id" n’aide pas non plus.

db2
la source
27

Voici un résumé de toutes les réponses concernant les avantages obtenus par la convention pour ne pas utiliser un nom commun pour toutes les clés primaires:

  • Moins d'erreurs, puisque les champs d'identité ne sont pas nommés de la même manière

    Vous ne pouvez pas écrire par erreur une requête qui se joint à la B.Id = B.Idplace de A.Id = B.Id, car les champs d'identité ne porteront jamais le même nom.

  • Noms de colonne plus clairs.

    Si vous regardez une colonne nommée CustomerId, vous savez immédiatement quelles données se trouvent dans cette colonne. Si le nom de la colonne était générique Id, vous devez également connaître le nom de la table pour savoir quelles données la colonne contient.

  • Evite les alias de colonnes inutiles

    Vous pouvez maintenant écrire à SELECT CustomerId, ProductIdpartir d'une requête qui se joint Customersà Products, au lieu deSELECT Customer.Id as CustomerId, Products.Id as ProductId

  • Permet la JOIN..USINGsyntaxe

    Vous pouvez joindre des tables avec la syntaxe Customer JOIN Products USING (CustomerId), au lieu deCustomer JOIN Products ON Customer.Id = Products.Id

  • La clé est plus facile à trouver dans les recherches

    Si vous recherchez le champ d'identité d'un client dans une solution volumineuse, la recherche de CustomerIdest beaucoup plus utile que la recherche deId

Si vous pouvez penser à d'autres avantages de cette convention d'appellation, faites-le moi savoir et je l'ajouterai à la liste.

Que vous choisissiez d'utiliser des noms de colonne uniques ou identiques pour les champs d'identité, c'est à vous de décider, peu importe ce que vous choisissez, soyez cohérent :)

Rachel
la source
12

Pour copier ma réponse à partir de la question liée:

Il existe une situation où coller "ID" sur chaque table n'est pas la meilleure idée: le USINGmot - clé, s'il est pris en charge. Nous l'utilisons souvent dans MySQL.

Par exemple, si vous avez fooTableavec colonne fooTableIdet barTableavec clé étrangère fooTableId, alors vos requêtes peuvent être construites de la manière suivante:

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

Il enregistre non seulement la frappe, mais est beaucoup plus lisible par rapport à la variante:

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

Après normalisation d'un schéma de base de données pour limiter la redondance, les tables sont divisées en tables plus petites avec des relations établies (un à un, un à plusieurs, plusieurs à plusieurs). Dans le processus, des champs uniques de la table d'origine peuvent apparaître dans plusieurs tables normalisées.

Par exemple, une base de données pour un blog pourrait ressembler à ceci dans sa forme non normalisée, en supposant une contrainte unique sur le nom d'auteur.

| 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 normaliser donnerait deux tables:

Auteur:

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

Poster

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

Author_Nickname serait ici une clé primaire pour la table author et une clé étrangère dans la table post. Même si Author_Nickname apparaît dans deux tableaux, cela correspond toujours à une seule unité d'information, c'est-à-dire. chaque nom de colonne correspond à un seul champ .

Dans de nombreux cas, il ne peut y avoir de contrainte unique sur les champs d'origine. Un champ artificiel numérique est donc utilisé comme clé primaire. Cela ne change pas le fait que chaque nom de colonne représente toujours un seul champ. Dans la conception de base de données traditionnelle, les noms de colonne individuels correspondent à des champs uniques même s'ils ne sont pas des clés. (Par exemple, on utiliserait part.partname et client.clientname plutôt que part.name et client.name ). C’est la raison de l’existence de la INNER JOIN ... USING <key>et des NATURAL JOINsyntaxes.

Cependant, de nos jours, et avec des couches ORM facilement disponibles dans de nombreuses langues, les bases de données sont souvent conçues comme une couche de persistance pour les langues OO, dans lesquelles il est naturel que les variables ayant le même rôle dans différentes classes soient appelées de la même manière ( part.name et client.name , pas part.partname et client.clientname ). Dans un tel contexte, j'ai tendance à utiliser "ID" pour mes clés primaires.

stilgar
la source
7

Un fournisseur tiers que nous avons embauché pour créer quelque chose pour nous a en fait nommé toutes ses colonnes d'identité Ident pour éviter d'utiliser Id.

Utiliser "Ident" au lieu de "Id" ne résout rien si "Ident" finit par être utilisé sur toutes leurs tables.

Un bon article sur les conventions de codage SQL sur le site Drupal indique une bonne pratique pour cette situation:

Il est recommandé de préfixer les noms de table avec le nom du module afin d'éviter tout conflit d'espace de nom.

De ce point de vue, CustomerProductId et AgencyGroupAssignmentId ont un sens à utiliser. Oui, c'est assez prolixe. Vous pourriez le raccourcir, mais le point le plus important à prendre en compte est de savoir si le développeur qui vous suit comprendra ou non votre intention . Les identifiants précédés de noms de table détaillés ne doivent pas laisser d'ambiguïté quant à leur nature. Et (pour moi), c'est plus important que de sauvegarder quelques frappes.

Aaron
la source
7

Je nomme mes colonnes CustomerID au lieu de ID, donc chaque fois que je tape

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

Invite SQL suggère immédiatement ce qui suit

ON c.CustomerID = o.CustomerID 

Cela me évite quelques frappes au clavier. Pourtant, je pense que les conventions de nommage sont très subjectives et en tant que telles, je n’ai pas d’opinion forte, d’une manière ou d’une autre.

AK
la source
5

C'est la même raison pour laquelle vous ne nommeriez pas tous vos champs varchar quelque chose comme "UserText" et "UserText1", ou pourquoi vous n'utiliseriez pas "UserDate" et "UserDate1".

En règle générale, si vous avez un champ d'identité dans une table, c'est votre clé primaire. Comment construiriez-vous une table enfant avec une clé étrangère en une table parent si la clé primaire dans les deux tables était id?

Tout le monde n'est pas d'accord avec cette méthode, mais dans mes bases de données, j'attribue une abréviation unique à chaque table. La PK de cette table s'appellerait PK_ [abbrv] ID. Si c'est utilisé comme FK n'importe où, j'utiliserais alors FK_ [abbrv] ID. Maintenant, je suppose que je ne travaille pas à déterminer quelles sont les relations entre les tables.

DForck42
la source
5

Fondamentalement, pour la même raison, vous ne nommez généralement pas les paramètres paramètre1, paramètre2 ... c’est exact, mais pas descriptif. Si vous voyez TableId, vous pouvez probablement supposer en toute sécurité qu'il est utilisé pour contenir un pk pour Table, quel que soit le contexte.

Quant à celui qui a utilisé Ident, il passe complètement à côté de la question, étant donné qu’il a le choix entre Ident et Id use Id. Ident est encore plus déroutant que Id.

Hors contexte, on peut supposer que Id est la clé primaire de certaines tables (ce qui n'est pas extrêmement utile, sauf si id est un guid), mais Ident ne vous dit même pas (ou du moins moi) que. Je finirais par comprendre que Ident est un raccourci pour l'identité (d'une manière ou d'une autre), mais le temps que j'ai passé à le découvrir serait gaspillé.

Jmoreno
la source
3

Utilisez un préfixe pour que le même nom puisse être utilisé dans les contextes de clé primaire et de clé étrangère, de manière à pouvoir exécuter natural join/ join ... using.

Dr Pizza
la source