Warum wird empfohlen, für eine Identitätsspalte nicht den Namen „ID“ zu verwenden?

68

Es wurde mir beigebracht, den Namen nicht Idfür die Identitätsspalte meiner Tabellen zu verwenden, aber in letzter Zeit habe ich ihn sowieso nur verwendet, weil er einfach, kurz und sehr aussagekräftig ist, was die Daten tatsächlich sind.

Ich habe Leute gesehen, die vorgeschlagen haben, Iddem Tabellennamen ein Präfix zu geben, aber dies scheint der Person, die die SQL-Abfragen schreibt (oder dem Programmierer, wenn Sie ein ORM wie Entity Framework verwenden), mehr Arbeit zu machen, insbesondere bei längeren Tabellennamen wie CustomerProductIdoderAgencyGroupAssignementId

Ein Drittanbieter, den wir beauftragt haben, etwas für uns zu erstellen, nannte tatsächlich alle seine Identitätsspalten, Identnur um die Verwendung zu vermeiden Id. Zuerst dachte ich, dass sie das taten, weil Ides ein Schlüsselwort war, aber als ich es untersuchte, stellte ich fest, dass dies Idin SQL Server 2005 kein Schlüsselwort ist, was wir verwenden.

Warum empfehlen die Leute, den Namen nicht Idfür eine Identitätsspalte zu verwenden?

Bearbeiten: Zur Verdeutlichung frage ich nicht, welche Benennungskonvention verwendet werden soll oder ob Argumente eine Benennungskonvention über der anderen verwenden sollen. Ich möchte nur wissen, warum es empfohlen wird, Idden Namen der Identitätsspalte nicht zu verwenden .

Ich bin ein einzelner Programmierer, kein DBA, und für mich ist die Datenbank nur ein Ort zum Speichern meiner Daten. Da ich normalerweise kleine Apps erstelle und normalerweise einen ORM für den Datenzugriff verwende, ist es viel einfacher, mit einem gemeinsamen Feldnamen für das Identitätsfeld zu arbeiten. Ich möchte wissen, was mir dabei entgeht und ob es wirklich gute Gründe gibt, dies nicht zu tun.

Rachel
quelle
10
BF bunfight hier schon: programmers.stackexchange.com/q/114728/5905 Mehrere von uns (lies: ich) haben sich
reingesogen
Gibt es wirklich eine solche Regel gegen die Verwendung von "id" als Name der Identitätsspalte? ActiveRecord, das Standard-ORM für Ruby on Rails, macht genau das gemäß Konvention. ar.rubyonrails.org
200_success
1
@ 200_success Auf Datenbankebene ja. Dies ist die Datenbank-Site, nicht die ORM-Site;)
JNK

Antworten:

46

Das Präfix des Tabellennamens hat sehr gute Gründe.

Erwägen:

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

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

Wir wollen DELETEaus TableADatensätzen, die in beiden Tabellen existieren. Ganz einfach, wir machen einfach Folgendes INNER JOIN:

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

.... und wir haben einfach alles ausgelöscht TableA. Wir haben versehentlich die ID von B mit sich selbst verglichen - jeder Datensatz stimmte überein und jeder Datensatz wurde gelöscht.

Wenn die Felder benannt worden wären TableAIdund TableBIddies unmöglich wäre ( Invalid field name TableAid in TableB).

Persönlich habe ich kein Problem damit, den Namen idin einer Tabelle zu verwenden, aber es ist wirklich eine bessere Praxis, ihn mit dem Tabellennamen (oder dem Entitätsnamen, wenn TableAdie Leute dann auch PeopleIdgut funktionieren würden) voranzustellen, um zu vermeiden, versehentlich mit dem falschen Feld zu vergleichen und zu blasen etwas auf.

Dies macht auch sehr deutlich, woher Felder in langen Abfragen mit vielen JOINs kommen.

JNK
quelle
10
Es handelt sich also im Grunde genommen um eine Namenskonvention zum Schutz vor Fehlern? Ich würde denken, mit begin transactionund commit transactionwäre eine bessere Übung, als (imo) ein widerlicheres Namensschema zu verwenden
Rachel
13
@ Rachel: Es ist für 1. Klarheit 2. Vermeiden Sie unnötige Spalten-Aliase 3. Erlauben Sie JOIN..USING 4. Ärgern Sie die PHP-Affen, die in einzelnen Objekten arbeiten, nicht in Mengen
GBN
4
@Rachel Wenn Sie den Fehler beim Schreiben der Abfrage nicht bemerkt haben und kurz bevor Sie sie ausgeführt haben, ist es unwahrscheinlich, dass Sie ihn vor dem Festschreiben bemerken. Dieses Zeug passiert, warum es wahrscheinlicher machen?
Andy
7
@Andy Ich versuche immer SELECT, meine Datensätze zu finden, bevor ich die ausführe DELETE, und sobald ich die Anweisung ausführe, überprüfe ich immer, ob die Zeilenzahl den Erwartungen entspricht, bevor ich sie festschreibe .
Rachel
5
@Rachel Schön, dass du etwas hast, das für dich funktioniert. Können Sie alle dazu bringen, das zu tun?
Andy
36

Meistens ist es, um zu verhindern, dass Fremdschlüssel zu einem enormen Schmerz werden. Angenommen, Sie haben zwei Tabellen: Customer und CustomerAddress. Der Primärschlüssel für beide ist eine Spalte mit dem Namen id, bei der es sich um eine Identitätsspalte (int) handelt.

Jetzt muss die Kunden-ID von CustomerAddress referenziert werden. Sie können die Spalten-ID natürlich nicht benennen, also entscheiden Sie sich für customer_id.

Dies führt zu einigen Problemen. Zunächst müssen Sie sich konsistent merken, wann die Spalte "id" und wann "customer_id" aufgerufen werden soll. Und wenn Sie dies vermasseln, führt dies zum zweiten Problem. Wenn Sie eine große Abfrage mit etwa einem Dutzend Joins haben und keine Daten zurückgeben, haben Sie Spaß beim Spielen von Where's Waldo und bei der Suche nach diesem Tippfehler:

ON c.id = ca.id

Whoops, hätte sein sollen ON c.id = ca.customer_id. Oder besser noch, benennen Sie Ihre Identitätsspalten beschreibend, so kann es sein ON c.customer_id = ca.customer_id. Wenn Sie dann versehentlich irgendwo den falschen Tabellenalias verwenden, wird customer_id nicht zu einer Spalte in dieser Tabelle, und es wird ein netter Kompilierungsfehler angezeigt, anstatt leere Ergebnisse und nachfolgendes Blinzeln des Codes.

Zugegeben, es gibt Fälle, in denen dies nicht hilft, z. B. wenn Sie mehrere Fremdschlüsselbeziehungen von einer Tabelle zu einer anderen benötigen, die Benennung aller Primärschlüssel "id" dort jedoch ebenfalls keine Hilfe darstellt.

db2
quelle
27

Hier ist eine Zusammenfassung aller Antworten zu den Vorteilen der Konvention, keinen gemeinsamen Namen für alle Primärschlüssel zu verwenden:

  • Weniger Fehler, da die Identitätsfelder nicht gleich heißen

    Sie können nicht versehentlich eine Abfrage schreiben, die sich B.Id = B.Idstattdessen anschließt A.Id = B.Id, da die Identitätsfelder niemals exakt gleich benannt werden.

  • Klarere Spaltennamen.

    Wenn Sie sich eine Spalte mit dem Namen ansehen CustomerId, wissen Sie sofort, welche Daten sich in dieser Spalte befinden. Wenn der Spaltenname ein generischer Name war Id, müssen Sie auch den Tabellennamen kennen, um zu wissen, welche Daten die Spalte enthält.

  • Vermeidet unnötige Spalten-Aliase

    Sie können jetzt SELECT CustomerId, ProductIdvon einer Abfrage aus schreiben , die Customersmit verknüpft ist Products, anstattSELECT Customer.Id as CustomerId, Products.Id as ProductId

  • Ermöglicht die JOIN..USINGSyntax

    Sie können Tabellen mit der Syntax Customer JOIN Products USING (CustomerId)anstelle von verknüpfenCustomer JOIN Products ON Customer.Id = Products.Id

  • Der Schlüssel ist bei der Suche leichter zu finden

    Wenn Sie in einer großen Lösung nach dem Identitätsfeld eines Kunden suchen, ist die Suche CustomerIdweitaus nützlicher als die SucheId

Wenn Sie sich andere Vorteile vorstellen können, die diese Namenskonvention hat, lassen Sie es mich wissen und ich werde es der Liste hinzufügen.

Es liegt an Ihnen, ob Sie eindeutige oder identische Spaltennamen für Identitätsfelder verwenden, aber unabhängig davon, was Sie auswählen, seien Sie bitte konsistent :)

Rachel
quelle
12

So kopieren Sie meine Antwort von der verknüpften Frage:

Es gibt eine Situation, in der es nicht die beste Idee ist, "ID" auf jeden Tisch zu kleben: das USINGSchlüsselwort, wenn es unterstützt wird. Wir verwenden es oft in MySQL.

Wenn Sie zum Beispiel fooTablemit Spalte fooTableIdund barTablemit Fremdschlüssel haben fooTableId, können Ihre Abfragen so konstruiert werden:

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

Das spart nicht nur Tipparbeit, sondern ist im Vergleich zur Alternative auch viel lesbarer:

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

Nach der Normalisierung eines Datenbankschemas zur Begrenzung der Redundanz werden Tabellen in kleinere Tabellen mit festgelegten Beziehungen unterteilt (eins zu eins, eins zu viele, viele zu viele). Dabei können einzelne Felder in der Originaltabelle in mehreren normalisierten Tabellen erscheinen.

Beispielsweise könnte eine Datenbank für ein Blog in ihrer nicht normalisierten Form so aussehen, wenn eine eindeutige Einschränkung für Author_Nickname angenommen wird.

| 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     |

Wenn Sie es normalisieren, erhalten Sie zwei Tabellen:

Autor:

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

Post

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

Hier wäre Author_Nickname ein Primärschlüssel für die Author-Tabelle und ein Fremdschlüssel in der Post-Tabelle. Auch wenn Author_Nickname in zwei Tabellen vorkommt, entspricht dies einer einzelnen Informationseinheit, d. H. Jeder Spaltenname entspricht einem einzelnen Feld .

In vielen Fällen kann es keine eindeutige Einschränkung für die ursprünglichen Felder geben, sodass stattdessen ein numerisches künstliches Feld als Primärschlüssel verwendet wird. Dies ändert nichts an der Tatsache, dass jeder Spaltenname immer noch ein einzelnes Feld darstellt. Im herkömmlichen Datenbankdesign entsprechen einzelne Spaltennamen einzelnen Feldern, auch wenn sie keine Schlüssel sind. ( ZB würde man part.partname und client.clientname anstelle von part.name und client.name verwenden ). Dies ist der Grund für die Existenz der INNER JOIN ... USING <key>und der NATURAL JOINSyntax.

Heutzutage und da ORM - Ebenen in vielen Sprachen verfügbar sind, werden Datenbanken häufig als Persistenz - Ebene für OO - Sprachen konzipiert, in denen natürlich Variablen, die in verschiedenen Klassen die gleiche Rolle spielen, als gleich bezeichnet werden ( part.name und client.name , nicht part.partname und client.clientname ). In einem solchen Kontext verwende ich normalerweise die ID für meine Primärschlüssel.

Stilgar
quelle
7

Ein Drittanbieter, den wir beauftragt haben, etwas für uns zu erstellen, nannte tatsächlich alle seine Identitätsspalten Ident, nur um die Verwendung von Id zu vermeiden.

Die Verwendung von "Ident" anstelle von "Id" löst eigentlich nichts, wenn "Ident" für alle Tabellen verwendet wird.

Es gibt einen guten Artikel über SQL-Kodierungskonventionen auf der Drupal-Site , der eine gute Praxis für diese Situation aufzeigt:

Es wird empfohlen, Tabellennamen mit dem Modulnamen als Präfix zu versehen, um mögliche Namespace-Konflikte zu vermeiden.

Unter diesem Gesichtspunkt ist es sinnvoll, CustomerProductId und AgencyGroupAssignmentId zu verwenden. Ja, es ist ziemlich ausführlich. Sie könnten es verkürzen, aber der größte Punkt, der Sie dann beschäftigen sollte, ist, ob der Entwickler, der Ihnen folgt, versteht, was Sie gemeint haben . IDs, denen ausführliche Tabellennamen vorangestellt sind, sollten keine Unklarheit darüber hinterlassen, was sie sind. Und (für mich) ist das wichtiger, als ein paar Tastenanschläge zu sparen.

Aaron
quelle
7

Ich benenne meine Spalten CustomerID anstelle von ID, also immer wenn ich tippe

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

SQL Prompt schlägt sofort Folgendes vor

ON c.CustomerID = o.CustomerID 

Das erspart mir ein paar Tastenanschläge. Trotzdem halte ich Namenskonventionen für sehr subjektiv und als solche habe ich nicht die eine oder andere feste Meinung.

AK
quelle
5

Aus dem gleichen Grund würden Sie nicht alle Ihre varchar-Felder mit "UserText" und "UserText1" benennen oder "UserDate" und "UserDate1" verwenden.

In der Regel ist ein Identitätsfeld in einer Tabelle Ihr Primärschlüssel. Wie würden Sie eine untergeordnete Tabelle mit einem Fremdschlüssel für eine übergeordnete Tabelle erstellen, wenn der Primärschlüssel in beiden Tabellen id wäre?

Nicht jeder ist mit dieser Methode einverstanden, aber in meinen Datenbanken ordne ich jeder Tabelle eine eindeutige Abkürzung zu. Die PK für diese Tabelle würde PK_ [Abkürzung] ID heißen. WENN das irgendwo als FK verwendet wird, würde ich FK_ [abbrv] ID verwenden. Jetzt muss ich keine Vermutung anstellen, um herauszufinden, wie die Tabellenbeziehungen aussehen.

DForck42
quelle
5

Grundsätzlich bezeichnen Sie Parameter parameter1, parameter2 ... aus demselben Grund normalerweise nicht als richtig, aber nicht beschreibend. Wenn Sie TableId sehen, können Sie wahrscheinlich davon ausgehen, dass es verwendet wird, um einen pk für Table zu speichern, unabhängig vom Kontext.

Wer auch immer Ident verwendet hat, verfehlt den Punkt völlig, wenn man zwischen Ident und Id use Id wählt. Ident ist noch verwirrender als Id.

Aus dem Zusammenhang heraus kann angenommen werden, dass ID der Primärschlüssel für eine Tabelle ist (nicht sehr nützlich, es sei denn, die ID ist eine Guid), aber Ident sagt es Ihnen (oder zumindest mir) nicht einmal. Ich würde irgendwann herausfinden, dass Ident die Abkürzung für Identität ist (auf die eine oder andere Weise), aber die Zeit, die ich damit verbracht habe, das herauszufinden, wäre verschwendet.

jmoreno
quelle
3

Verwenden Sie ein Präfix, damit derselbe Name sowohl im Primärschlüssel- als auch im Fremdschlüsselkontext verwendet werden kann, damit Sie natural join/ ausführen können join ... using.

DrPizza
quelle