Je me demandais les opinions des gens sur le nom des colonnes ID dans les tables de base de données.
Si j'ai une table appelée Factures avec une clé primaire d'une colonne d'identité, j'appellerais cette colonne InvoiceID afin de ne pas entrer en conflit avec d'autres tables et il est évident de quoi il s'agit.
Là où je travaille, ils ont appelé toutes les colonnes ID ID.
Ils feraient donc ce qui suit:
Select
i.ID
, il.ID
From
Invoices i
Left Join InvoiceLines il
on i.ID = il.InvoiceID
Maintenant, je vois quelques problèmes ici:
1. Vous devez alias les colonnes sur la sélection
2. ID = InvoiceID ne rentre pas dans mon cerveau
3. Si vous n'avez pas alias les tables et fait référence à InvoiceID, est-il évident sur quelle table il se trouve?
Que pensent les autres sur le sujet?
L'ID est un SQL Antipattern. Voir http://www.Amazon.com/s/ref=nb_sb_ss_i_1_5?url=search-alias%3Dstripbooks&field-keywords=sql+antipatterns&sprefix=sql+a
Si vous avez de nombreuses tables avec ID comme identifiant, vous rendez les rapports beaucoup plus difficiles. Il obscurcit le sens et rend les requêtes complexes plus difficiles à lire et vous oblige à utiliser des alias pour différencier le rapport lui-même.
De plus, si quelqu'un est assez stupide pour utiliser une jointure naturelle dans une base de données où il est disponible, vous vous joindrez aux mauvais enregistrements.
Si vous souhaitez utiliser la syntaxe USING autorisée par certains dbs, vous ne pouvez pas si vous utilisez ID.
Si vous utilisez ID, vous pouvez facilement vous retrouver avec une jointure erronée s'il vous arrive de copier la syntaxe de jointure (ne me dites pas que personne ne le fait jamais!) Et oubliez de changer l'alias dans la condition de jointure.
Vous avez donc maintenant
select t1.field1, t2.field2, t3.field3
from table1 t1
join table2 t2 on t1.id = t2.table1id
join table3 t3 on t1.id = t3.table2id
quand tu voulais dire
select t1.field1, t2.field2, t3.field3
from table1 t1
join table2 t2 on t1.id = t2.table1id
join table3 t3 on t2.id = t3.table2id
Si vous utilisez tablenameID comme champ id, ce type d'erreur accidentelle est beaucoup moins susceptible de se produire et beaucoup plus facile à trouver.
J'ai toujours préféré ID à TableName + ID pour la colonne id puis TableName + ID pour une clé étrangère. De cette façon, toutes les tables ont le même nom pour le champ id et il n'y a pas de description redondante. Cela me semble plus simple car toutes les tables ont le même nom de champ de clé primaire.
Pour ce qui est de joindre des tables et de ne pas savoir quel champ Id appartient à quelle table, à mon avis, la requête doit être écrite pour gérer cette situation. Là où je travaille, nous précédons toujours les champs que nous utilisons dans une instruction avec l'alias table/table.
Récemment, il y a eu un combat de nerd à propos de cette chose en ma compagnie. L'avènement de LINQ a rendu le modèle redondant tablename + ID encore plus évident à mes yeux. Je pense que la plupart des gens raisonnables diront que si vous écrivez à la main votre SQL de telle manière que vous devez spécifier des noms de table pour différencier FKs alors ce n'est pas seulement une économie de frappe, mais il ajoute de la clarté à votre SQL pour n'utiliser que l'ID dans lequel vous pouvez voir clairement quel est le [~ # ~] pk [~ # ~] et qui est le [~ # ~] fk [~ # ~].
Par exemple.
DES EMPLOYÉS e GAUCHEZ LES CLIENTS c ON e.ID = c.EmployeeID
me dit non seulement que les deux sont liés, mais quel est le [~ # ~] pk [~ # ~] et qui est le = [~ # ~] fk [~ # ~]. Alors que dans l'ancien style, vous êtes obligé de regarder ou d'espérer qu'ils ont bien été nommés.
Nous utilisons InvoiceID
, pas ID
. Cela rend les requêtes plus lisibles - lorsque vous voyez ID
seul, cela peut signifier quelque chose, surtout lorsque vous aliasez la table sur i
.
Je suis d'accord avec Keven et quelques autres personnes ici que le PK pour une table doit simplement être Id et les clés étrangères listent l'ID OtherTable +.
Cependant, je voudrais ajouter une raison qui a récemment donné plus de poids à cet argument.
Dans ma position actuelle, nous utilisons le cadre d'entité à l'aide de la génération POCO. En utilisant la convention de dénomination standard de l'ID, le PK permet l'héritage d'une classe de base poco avec validation et ainsi de suite pour les tables qui partagent un ensemble de noms de colonnes communs. L'utilisation de Tablename + Id comme PK pour chacune de ces tables détruit la possibilité d'utiliser une classe de base pour celles-ci.
Seulement un peu de matière à réflexion.
Ma préférence est également l'ID pour la clé primaire et TableNameID pour la clé étrangère. J'aime aussi avoir une colonne "nom" dans la plupart des tableaux où je détiens l'identifiant lisible par l'utilisateur (c'est-à-dire le nom :-)) de l'entrée. Cette structure offre une grande flexibilité dans l'application elle-même, je peux gérer des tables en masse, de la même manière. C'est une chose très puissante. Habituellement, un logiciel OO est construit au-dessus de la base de données, mais l'ensemble d'outils OO ne peut pas être appliqué car la base de données elle-même ne le permet pas. Avoir l'ID des colonnes et le nom n'est toujours pas très bon, mais c'est une étape.
Sélectionner
i.ID, il.ID à partir des factures i gauche Joindre les lignes de facture il sur i.ID = il.InvoiceID
Pourquoi je ne peux pas faire ça?
Select
Invoices.ID
, InvoiceLines.ID
From
Invoices
Left Join InvoiceLines
on Invoices.ID = InvoiceLines.InvoiceID
À mon avis, c'est très lisible et simple. Nommer des variables comme i et il est un mauvais choix en général.
Ce n'est pas vraiment important, vous risquez de rencontrer des problèmes similaires dans toutes les conventions de dénomination.
Mais il est important d'être cohérent pour ne pas avoir à regarder les définitions de table à chaque fois que vous écrivez une requête.
Je viens de commencer à travailler dans un endroit qui utilise uniquement "ID" (dans les tables de base, référencé par TableNameID dans les clés étrangères), et j'ai déjà trouvé DEUX problèmes de production directement causés par celui-ci.
Dans un cas, la requête a utilisé "... où ID dans (SELECT ID FROM OtherTable ..." au lieu de "... où ID dans (SELECT TransID FROM OtherTable ...".
Quelqu'un peut-il honnêtement dire que cela n'aurait pas été beaucoup plus facile à repérer si des noms complets et cohérents avaient été utilisés là où la mauvaise déclaration aurait dit "... où TransID dans (SELECT OtherTableID from OtherTable ..."? Je ne pense pas donc.
L'autre problème se produit lors de la refactorisation du code. Si vous utilisez une table temporaire alors qu'auparavant la requête sortait d'une table principale, alors l'ancien code lit "... dbo.MyFunction (t.ID) ..." et si cela n'est pas modifié mais "t" fait maintenant référence à un table temporaire au lieu de la table de base, vous n'obtenez même pas d'erreur - juste des résultats erronés.
Si générer des erreurs inutiles est un objectif (peut-être que certaines personnes n'ont pas assez de travail?), Ce type de convention de dénomination est idéal. Sinon, une dénomination cohérente est la voie à suivre.
Par souci de simplicité, la plupart des gens nomment la colonne sur l'ID de la table. S'il a une référence de clé étrangère sur une autre table, alors ils l'appellent explicitement InvoiceID (pour utiliser votre exemple) dans le cas des jointures, vous aliasez la table de toute façon, de sorte que l'inv.ID explicite est toujours plus simple que inv.InvoiceID
Venant à cela du point de vue d'un dictionnaire de données formel, je nommerais l'élément de données invoice_ID
. Généralement, un nom d'élément de données sera unique dans le dictionnaire de données et aura idéalement le même nom partout, bien que parfois des termes de qualification supplémentaires puissent être requis en fonction du contexte, par ex. l'élément de données nommé employee_ID
pourrait être utilisé deux fois dans l'organigramme et donc qualifié de supervisor_employee_ID
et subordinate_employee_ID
respectivement.
De toute évidence, les conventions de dénomination sont subjectives et une question de style. J'ai trouvé les directives ISO/IEC 11179 comme un point de départ utile.
Pour le SGBD, je vois les tables comme des collections d'entités (sauf celles qui ne contiennent qu'une seule ligne, par exemple table cofig, table de constantes, etc.) par exemple la table où mon employee_ID
est la clé qui serait nommée Personnel
. Donc tout de suite la convention TableNameID
ne fonctionne pas pour moi.
J'ai vu le TableName.ID=PK TableNameID=FK
style utilisé sur les grands modèles de données et je dois dire que je le trouve un peu déroutant: je préfère de loin le nom d'un identifiant, c'est-à-dire qu'il ne change pas de nom en fonction de la table dans laquelle il apparaît. Quelque chose à noter est le style susmentionné semble être utilisé dans les boutiques qui ajoutent une colonne IDENTITY
(incrémentation automatique) à la table every tout en évitant les clés naturelles et composées dans les clés étrangères. Ces magasins n'ont généralement pas de dictionnaires de données formels ni construits à partir de modèles de données. Encore une fois, ce n'est qu'une question de style et à laquelle je ne souscris pas personnellement. Donc finalement, ce n'est pas pour moi.
Cela dit, je peux voir un cas pour parfois supprimer le qualificateur du nom de la colonne lorsque le nom de la table fournit un contexte pour le faire, par exemple l'élément nommé employee_last_name
peut devenir simplement last_name
dans la table Personnel
. La raison ici est que le domaine est le 'nom de famille des gens' et est plus susceptible d'être UNION
ed avec last_name
colonnes de d'autres tables plutôt que d'être utilisées comme clé étrangère in une autre table, mais là encore ... Je pourrais juste changer d'avis, parfois vous ne pouvez jamais dire . C'est la chose: la modélisation des données est en partie de l'art, en partie de la science.
Je personnellement préfère (comme cela a été indiqué ci-dessus) le Table.ID pour le PK et TableID pour le FK . Même (veuillez ne pas me tirer dessus), Microsoft Access le recommande.
CEPENDANT, je sais également que certains outils de génération favorisent le TableID pour PK car ils ont tendance à lier tous les noms de colonnes qui contiennent 'ID' dans le mot, ID COMPRIS !!!
Même le concepteur de requêtes le fait sur Microsoft SQL Server (et pour chaque requête que vous créez, vous finissez par arracher toutes les relations nouvellement créées inutiles sur toutes les tables de l'ID de colonne)
AINSI que mon OCD interne le déteste, je roule avec la convention TableID. Souvenons-nous que cela s'appelle une base de données , car ce sera la base pour de nombreuses applications à venir. Et toutes les technologies devraient bénéficier d'un schéma bien normalisé avec une description claire.
Il va sans dire que je dessine ma ligne lorsque les gens commencent à utiliser TableName, TableDescription et autres. À mon avis, les conventions devraient faire ce qui suit:
Alias de table: nom de table complet, singularisé. Ex.
SELECT Employee.*, eMail.Address
FROM Employees AS Employee LEFT JOIN eMails as eMail on Employee.eMailID = eMail.eMailID -- I would sure like it to just have the eMail.ID here.... but oh well
[Mise à jour]
En outre, il y a des messages valides dans ce fil sur les colonnes dupliquées en raison du "type de relation" ou du rôle. Exemple, si un magasin a un EmployeeID, qui me dit squat. Je fais donc parfois quelque chose comme Store.EmployeeID_Manager. Bien sûr, c'est un peu plus grand, mais au moins les gens ne deviendront pas fous en essayant de trouver la table ManagerID , ou quoi EmployeeID y fait. Lorsque l'interrogation est OERE je le simplifierais comme: SELECT EmployeeID_Manager as ManagerID FROM Store
Je pense que vous pouvez utiliser n'importe quoi pour le "ID" tant que vous êtes cohérent. Il est important d'inclure le nom de la table. Je suggérerais d'utiliser un outil de modélisation comme Erwin pour appliquer les conventions et les normes de dénomination. Ainsi, lors de l'écriture de requêtes, il est facile de comprendre les relations qui peuvent exister entre les tables.
Ce que je veux dire par la première déclaration, c'est qu'au lieu d'ID, vous pouvez utiliser quelque chose d'autre comme "recno". Ainsi, cette table aurait un PK de facture_recno et ainsi de suite.
À la vôtre, Ben
Mon vote est pour InvoiceID pour l'ID de table. J'utilise également la même convention de dénomination lorsqu'elle est utilisée comme clé étrangère et j'utilise des noms d'alias intelligents dans les requêtes.
Select Invoice.InvoiceID, Lines.InvoiceLine, Customer.OrgName
From Invoices Invoice
Join InvoiceLines Lines on Lines.InvoiceID = Invoice.InvoiceID
Join Customers Customer on Customer.CustomerID = Invoice.CustomerID
Bien sûr, c'est plus long que certains autres exemples. Mais souris. C'est pour la postérité et un jour, un pauvre codeur junior devra modifier votre chef-d'œuvre. Dans cet exemple, il n'y a aucune ambiguïté et à mesure que des tables supplémentaires seront ajoutées à la requête, vous serez reconnaissant pour la verbosité.
Ce que je fais pour garder les choses cohérentes pour moi (où une table a une clé primaire à une seule colonne utilisée comme ID) est de nommer la clé primaire de la table Table_pk
. Partout où j'ai une clé étrangère pointant vers la clé primaire de cette table, j'appelle la colonne PrimaryKeyTable_fk
. De cette façon, je sais que si j'ai un Customer_pk
dans ma table Client et un Customer_fk
dans ma table Order, je sais que la table Order fait référence à une entrée de la table Customer.
Pour moi, cela a du sens en particulier pour les jointures où je pense que cela se lit plus facilement.
SELECT *
FROM Customer AS c
INNER JOIN Order AS c ON c.Customer_pk = o.Customer_fk
Si vous donnez à chaque clé un nom unique, par ex. "factures.invoice_id" au lieu de "factures.id", alors vous pouvez utiliser les opérateurs "jointure naturelle" et "utilisation" sans aucun souci. Par exemple.
SELECT * FROM invoices NATURAL JOIN invoice_lines
SELECT * FROM invoices JOIN invoice_lines USING (invoice_id)
au lieu de
SELECT * from invoices JOIN invoice_lines
ON invoices.id = invoice_lines.invoice_id
SQL est suffisamment verbeux sans le rendre plus verbeux.
Pour le nom de colonne dans la base de données, j'utiliserais "InvoiceID".
Si je copie les champs dans une structure sans nom via LINQ, je peux le nommer "ID", s'il s'agit du seul ID dans la structure.
Si la colonne ne va PAS être utilisée dans une clé étrangère, de sorte qu'elle ne sert qu'à identifier de manière unique une ligne pour la modification, la modification ou la suppression, je la nommerai "PK".
FWIW, notre nouveau standard (qui change, euh, je veux dire "évolue", à chaque nouveau projet) est:
pk_
le préfixe signifie la clé primaire_id
suffixe signifie un identifiant entier à incrémentation automatiquefk_
préfixe signifie clé étrangère (aucun suffixe nécessaire)_VW
suffixe pour les vuesis_
préfixe pour les booléensAinsi, une table nommée NAMES peut avoir les champs pk_name_id, first_name, last_name, is_alive,
et fk_company
et une vue appelée LIVING_CUSTOMERS_VW
, défini comme:
CHOISIR prénom, nom DANS CONTACT.NOMS OERE (is_alive = 'True')
Comme d'autres l'ont dit, cependant, à peu près n'importe quel schéma fonctionnera tant qu'il est cohérent et n'obscurcit pas inutilement vos significations.
Je préfère DomainName || 'ID'. (c'est-à-dire DomainName + ID)
DomainName est souvent, mais pas toujours, identique à TableName.
Le problème avec l'ID à lui seul est qu'il ne s'agrandit pas. Une fois que vous avez environ 200 tables, chacune avec une première colonne nommée ID, les données commencent à se ressembler. Si vous qualifiez toujours l'ID avec le nom de la table, cela aide un peu, mais pas tant que ça.
DomainName & ID peut être utilisé pour nommer des clés étrangères ainsi que des clés primaires. Lorsque les clés foriegn sont nommées d'après la colonne à laquelle elles font référence, cela peut être d'une aide mnémonique. Formellement, il n'est pas nécessaire de lier le nom d'une clé étrangère à la clé qu'elle référence, car la contrainte d'intégrité référentielle établira la référence. Mais c'est extrêmement pratique quand il s'agit de lire des requêtes et des mises à jour.
Parfois, DomainName || 'ID' ne peut pas être utilisé, car il y aurait deux colonnes dans la même table avec le même nom. Exemple: Employees.EmployeeID et Employees.SupervisorID. Dans ces cas, j'utilise RoleName || 'ID', comme dans l'exemple.
Enfin et surtout, j'utilise des clés naturelles plutôt que synthétiques lorsque cela est possible. Il existe des situations où les clés naturelles ne sont pas disponibles ou non fiables, mais il existe de nombreuses situations où la clé naturelle est le bon choix. Dans ces cas, je laisse la clé naturelle prendre le nom qu'elle aurait naturellement. Souvent, ce nom ne contient même pas les lettres "ID". Exemple: OrderNo où No est l'abréviation de "Number".
Pour chaque table, je choisis un raccourci de lettre d'arbre (par exemple, Employés => Emp)
De cette façon, une clé primaire numérique automatique devient nkEmp.
Il est court, unique dans toute la base de données et je connais exactement ses propriétés en un coup d'œil.
Je garde les mêmes noms en SQL et dans tous les langages que j'utilise (principalement C #, Javascript, VB6).
Voir les conventions de dénomination du site Interakt pour un système bien pensé de dénomination des tables et des colonnes. La méthode utilise un suffixe pour chaque table (_prd
pour une table de produits, ou _ctg
pour un tableau de catégories) et l'ajoute à chaque colonne d'un tableau donné. La colonne d'identité de la table des produits serait donc id_prd
et est donc unique dans la base de données.
Ils vont encore plus loin pour aider à comprendre les clés étrangères: la clé étrangère dans la table des produits qui fait référence à la table des catégories serait idctg_prd
pour qu'il soit évident à quelle table il appartient (_prd
suffixe) et à quel tableau il fait référence (catégorie).
Les avantages sont qu'il n'y a pas d'ambiguïté avec les colonnes d'identité dans différentes tables et que vous pouvez voir en un coup d'œil à quelles colonnes une requête fait référence par les noms de colonne.
Je déteste le nom simple. Je préfère fortement utiliser toujours la facture_id ou une variante de celle-ci. Je sais toujours quelle table est la table faisant autorité pour l'id quand je dois, mais cela me confond
SELECT * from Invoice inv, InvoiceLine inv_l where
inv_l.InvoiceID = inv.ID
SELECT * from Invoice inv, InvoiceLine inv_l where
inv_l.ID = inv.InvoiceLineID
SELECT * from Invoice inv, InvoiceLine inv_l where
inv_l.ID = inv.InvoiceID
SELECT * from Invoice inv, InvoiceLine inv_l where
inv_l.InvoiceLineID = inv.ID
Le pire de tout, c'est le mélange que vous mentionnez, totalement déroutant. J'ai dû travailler avec une base de données où presque toujours c'était foo_id sauf dans l'un des identifiants les plus utilisés. C'était l'enfer total.
Je suis définitivement d'accord avec l'inclusion du nom de la table dans le nom du champ ID, pour exactement les raisons que vous donnez. Généralement, c'est le seul champ où j'inclurais le nom de la table.