Kann ich mehrere Primärschlüssel in einer einzigen Tabelle haben?


Antworten:


559

Eine Tabelle kann einen zusammengesetzten Primärschlüssel haben, bei dem es sich um einen Primärschlüssel handelt, der aus zwei oder mehr Spalten besteht. Zum Beispiel:

CREATE TABLE userdata (
  userid INT,
  userdataid INT,
  info char(200),
  primary key (userid, userdataid)
);

Update: Hier ist ein Link mit einer detaillierteren Beschreibung der zusammengesetzten Primärschlüssel.


2
In diesem Beispiel werden sowohl die Benutzer-ID als auch die Benutzerdaten-ID benötigt, um eine eindeutige Zeile zu identifizieren / zu finden. Ich bin mir nicht sicher, was die Absicht des OP war, aber ich kam hierher, um zu sehen, ob ich eine Zeile mit einem Schlüsselsatz eindeutig identifizieren konnte. Zum Beispiel möchte ich einen eindeutigen Benutzer entweder mit einem Benutzernamen oder einer Benutzer-ID identifizieren, ohne beide zu benötigen. Ich denke, RBs Antwort auf eindeutige Indizes würde dort den Trick machen.
Burrito

1
@Benitok Wie in der Antwort von RB. erwähnt , können Sie eindeutige Indizes verwenden, um das zu tun, wonach Sie suchen (eine eindeutige, indizierte Spalte, unabhängig von anderen eindeutigen, indizierten Spalten in derselben Tabelle). Lesen Sie unbedingt Ihre spezifische Version des SQL-Handbuchs, um Einzelheiten zur genauen verwendeten Sprachsyntax zu erfahren.
4 Uhr morgens,

195

Sie können nur einen Primärschlüssel haben, aber Sie können mehrere Spalten in Ihrem Primärschlüssel haben.

Sie können auch eindeutige Indizes in Ihrer Tabelle haben, die ein bisschen wie ein Primärschlüssel funktionieren, da sie eindeutige Werte erzwingen und die Abfrage dieser Werte beschleunigen.


39

Eine Tabelle kann mehrere Kandidatenschlüssel haben. Jeder Kandidatenschlüssel ist eine Spalte oder ein Satz von Spalten, die EINZIGARTIG, zusammengenommen und auch NICHT NULL sind. Die Angabe von Werten für alle Spalten eines Kandidatenschlüssels reicht daher aus, um festzustellen, ob eine Zeile die Kriterien erfüllt oder überhaupt keine Zeilen.

Kandidatenschlüssel sind ein grundlegendes Konzept im relationalen Datenmodell.

Wenn mehrere Schlüssel in einer Tabelle vorhanden sind, ist es üblich, einen der Kandidatenschlüssel als Primärschlüssel zu bestimmen. Es ist auch üblich, dass Fremdschlüssel in der Tabelle auf den Primärschlüssel verweisen und nicht auf einen anderen Kandidatenschlüssel.

Ich empfehle diese Vorgehensweisen, aber es gibt nichts im relationalen Modell, das die Auswahl eines Primärschlüssels unter den Kandidatenschlüsseln erfordert.


5
Einverstanden. Alle Schlüssel sind im logischen Modell gleich (keiner ist 'primär'). Die Wahl, welcher Schlüssel in der physischen Implementierung die Bezeichnung PRIMARY KEY erhält, hängt vom Arbitray und vom Hersteller / Produkt ab.
Tag, wenn

3
Ich würde sagen, dass es vom Datenbankdesigner abhängig ist.
Walter Mitty

Ich bin gerade auf einen Anwendungsfall gestoßen, bei dem dies erforderlich ist. Ich habe eine Tabelle, die von Entity Framework erstellt / verwaltet wird. Soweit ich das beurteilen kann, werden derzeit keine eindeutigen zusammengesetzten Einschränkungen für Nicht-Primärschlüssel unterstützt. Es werden jedoch zusammengesetzte Primärschlüssel unterstützt. Die Daten werden auch mit einem entfernten Datenbanksystem verknüpft, das überhaupt keine zusammengesetzten Schlüssel unterstützt. Ich habe eine zusammengesetzte PK in EF erstellt, aber auch eine nicht nullfähige GUID-Spalte hinzugefügt, anhand derer sich das andere System eindeutig identifizieren kann.
Chris Nevill

2
Chris, ich sagte, dass das relationale Modell keine Primärschlüssel benötigt. Ich habe nichts darüber gesagt, ob ein Tool sie benötigt. Aber ich verstehe Ihren Standpunkt.
Walter Mitty

Ich denke, es gibt eine Anforderung, dass die PK minimal sein muss, dh die geringste Anzahl von Spalten verwendet, um jeden Datensatz eindeutig zu identifizieren.
Gary

14

Dies ist die Antwort sowohl auf die Hauptfrage als auch auf @ Kalmis Frage von

Was wäre der Sinn, wenn mehrere Spalten automatisch generiert würden?

Dieser Code unten hat einen zusammengesetzten Primärschlüssel. Eine seiner Spalten wird automatisch inkrementiert. Dies funktioniert nur in MyISAM. InnoDB generiert den Fehler " ERROR 1075 (42000): Falsche Tabellendefinition; es kann nur eine automatische Spalte geben, die als Schlüssel definiert werden muss ".

DROP TABLE IF EXISTS `test`.`animals`;
CREATE TABLE  `test`.`animals` (
  `grp` char(30) NOT NULL,
  `id` mediumint(9) NOT NULL AUTO_INCREMENT,
  `name` char(30) NOT NULL,
  PRIMARY KEY (`grp`,`id`)
) ENGINE=MyISAM;

INSERT INTO animals (grp,name) VALUES
    ('mammal','dog'),('mammal','cat'),
    ('bird','penguin'),('fish','lax'),('mammal','whale'),
    ('bird','ostrich');

SELECT * FROM animals ORDER BY grp,id;

Which returns:

+--------+----+---------+
| grp    | id | name    |
+--------+----+---------+
| fish   |  1 | lax     |
| mammal |  1 | dog     |
| mammal |  2 | cat     |
| mammal |  3 | whale   |
| bird   |  1 | penguin |
| bird   |  2 | ostrich |
+--------+----+---------+

2
Dies funktioniert, wenn Sie die Spalte für die automatische Inkrementierung zuerst in der Primärschlüsseldefinition angeben. (Vielleicht hat sich das geändert, ich habe es gerade in 5.6 getestet)
CTarczon

11

(Haben diese viel studiert)

Kandidatenschlüssel - Eine minimale Spaltenkombination, die erforderlich ist, um eine Tabellenzeile eindeutig zu identifizieren.
Zusammengesetzte Schlüssel - 2 oder mehr Spalten.

  • In einer Tabelle können mehrere Kandidatenschlüssel vorhanden sein.
    • Primärschlüssel - Nur einer der von uns ausgewählten Kandidatenschlüssel
    • Alternative Schlüssel - Alle anderen Kandidatenschlüssel
      • Sowohl Primärschlüssel als auch Alternativschlüssel können zusammengesetzte Schlüssel sein

Quellen:
https://en.wikipedia.org/wiki/Superkey
https://en.wikipedia.org/wiki/Candidate_key
https://en.wikipedia.org/wiki/Primary_key
https://en.wikipedia.org / wiki / Compound_key


6

Wie von den anderen angemerkt, ist es möglich, mehrspaltige Primärschlüssel zu haben. Es sollte jedoch beachtet werden, dass Sie in Betracht ziehen sollten, Ihre Beziehung zu normalisieren , wenn Sie einige funktionale Abhängigkeiten haben , die nicht durch einen Schlüssel eingeführt werden .

Beispiel:

Person(id, name, email, street, zip_code, area)

Es kann eine funktionale Abhängigkeit zwischen geben. id -> name,email, street, zip_code and area Oft zip_codeist jedoch a mit a verbunden, areaund daher besteht eine interne funktionale Abhängigkeit zwischen zip_code -> area.

Daher kann man in Betracht ziehen, es in eine andere Tabelle aufzuteilen:

Person(id, name, email, street, zip_code)
Area(zip_code, name)

Damit stimmt es mit der dritten Normalform überein .


6

Der Primärschlüssel ist aufgrund der Konnotation von "Primär" und der unbewussten Assoziation mit dem logischen Modell eine sehr unglückliche Notation. Ich vermeide es daher, es zu benutzen. Stattdessen beziehe ich mich auf den Ersatzschlüssel des physikalischen Modells und die natürlichen Schlüssel des logischen Modells.

Es ist wichtig, dass das logische Modell für jede Entität mindestens einen Satz von "Geschäftsattributen" aufweist, die einen Schlüssel für die Entität enthalten. Boyce, Codd, Date et al. Bezeichnen diese im relationalen Modell als Kandidatenschlüssel. Wenn wir dann Tabellen für diese Entitäten erstellen, werden ihre Kandidatenschlüssel zu natürlichen Schlüsseln in diesen Tabellen. Nur über diese natürlichen Schlüssel können Benutzer Zeilen in den Tabellen eindeutig identifizieren. als Ersatzschlüssel sollten immer vor Benutzern verborgen bleiben. Dies liegt daran, dass Ersatzschlüssel keine geschäftliche Bedeutung haben.

Das physikalische Modell für unsere Tabellen ist jedoch in vielen Fällen ohne Ersatzschlüssel ineffizient. Denken Sie daran, dass nicht abgedeckte Spalten für einen nicht gruppierten Index (im Allgemeinen) nur über eine Schlüsselsuche im gruppierten Index gefunden werden können (ignorieren Sie Tabellen, die für einen Moment als Heaps implementiert sind). Wenn unsere verfügbaren natürlichen Schlüssel breit sind, vergrößert dies (1) die Breite unserer nicht gruppierten Blattknoten, wodurch die Speicheranforderungen und Lesezugriffe für Suchvorgänge und Scans dieses nicht gruppierten Index erhöht werden. und (2) verringert das Fan-out von unserem Clustered-Index, wodurch die Indexhöhe und die Indexgröße erhöht werden, wodurch wiederum die Lese- und Speicheranforderungen für unsere Clustered-Indizes erhöht werden; und (3) erhöht die Cache-Anforderungen für unsere Clustered-Indizes. andere Indizes und Daten aus dem Cache jagen.

Hier erweist sich ein kleiner Ersatzschlüssel, der dem RDBMS als "Primärschlüssel" bezeichnet wird, als vorteilhaft. Bei der Festlegung als Clustering-Schlüssel für die Suche nach Schlüsseln in den Clustered-Index aus nicht gruppierten Indizes und nach Fremdschlüssel-Lookups aus verwandten Tabellen verschwinden alle diese Nachteile. Unsere Clustered-Index-Fan-Outs erhöhen sich erneut, um die Höhe und Größe der Clustered-Indizes zu verringern, die Cache-Last für unsere Clustered-Indizes zu verringern und die Lesevorgänge beim Zugriff auf Daten über einen beliebigen Mechanismus zu verringern (ob Index-Scan, Index-Suche, Nicht-Clustered-Key-Lookup oder Fremdschlüssel-Lookup). und verringern Sie die Speicheranforderungen für Clustered- und Nonclustered-Indizes unserer Tabellen.

Beachten Sie, dass diese Vorteile nur auftreten, wenn der Ersatzschlüssel sowohl klein als auch der Clusterschlüssel ist. Wenn eine GUID als Clustering-Schlüssel verwendet wird, ist die Situation häufig schlechter als wenn der kleinste verfügbare natürliche Schlüssel verwendet wurde. Wenn die Tabelle als Heap organisiert ist, wird die 8-Byte-RowID (Heap) für die Schlüsselsuche verwendet. Dies ist besser als eine 16-Byte-GUID, aber weniger leistungsfähig als eine 4-Byte-Ganzzahl.

Wenn aus geschäftlichen Gründen eine GUID verwendet werden muss, lohnt sich die Suche nach einem besseren Clustering-Schlüssel. Wenn beispielsweise eine kleine Standortkennung und eine 4-Byte- "Standortsequenznummer" möglich sind, bietet dieses Design möglicherweise eine bessere Leistung als eine GUID als Ersatzschlüssel.

Wenn die Konsequenzen eines Heaps (möglicherweise Hash-Join) den bevorzugten Speicher ausmachen, müssen die Kosten eines breiteren Clustering-Schlüssels in die Kompromissanalyse einbezogen werden.

Betrachten Sie dieses Beispiel:

ALTER TABLE Persons
ADD CONSTRAINT pk_PersonID PRIMARY KEY (P_Id,LastName)

Wenn das Tupel " (P_Id, Nachname) " eine Eindeutigkeitsbeschränkung erfordert und ein langer Unicode-Nachname plus eine 4-Byte-Ganzzahl sein kann, wäre es wünschenswert, (1) diese Einschränkung deklarativ als " ADD CONSTRAINT pk_PersonID UNIQUE NONCLUSTERED (P_Id ") zu erzwingen , LastName) "und (2) deklarieren einen kleinen Ersatzschlüssel separat als" Primärschlüssel "eines Clustered-Index. Es ist erwähnenswert, dass Anita möglicherweise nur den Nachnamen zu dieser Einschränkung hinzufügen möchte, um daraus ein abgedecktes Feld zu machen, was in einem Clustered-Index nicht erforderlich ist, da ALLE Felder von diesem abgedeckt werden.

Die Fähigkeit in SQL Server, einen Primärschlüssel als nicht gruppiert zu kennzeichnen, ist ein unglücklicher historischer Umstand, da die Bedeutung "bevorzugter natürlicher Schlüssel oder Kandidatenschlüssel" (aus dem logischen Modell) mit der Bedeutung "Suchschlüssel im Speicher" aus dem physischen Bereich verschmolzen ist Modell. Meines Wissens nach verwendete SYBASE SQL Server ursprünglich immer eine 4-Byte-RowID, ob in einem Heap oder einem Clustered-Index, als "Suchschlüssel im Speicher" aus dem physischen Modell.


3
Können Sie das bitte ins Englische übersetzen?
Jasir

3

Einige Leute verwenden den Begriff "Primärschlüssel", um genau eine Ganzzahlspalte zu bezeichnen, deren Werte durch einen automatischen Mechanismus generiert werden. Zum Beispiel AUTO_INCREMENTin MySQL oder IDENTITYin Microsoft SQL Server. Verwenden Sie in diesem Sinne den Primärschlüssel?

Wenn ja, hängt die Antwort von der Marke der Datenbank ab, die Sie verwenden. In MySQL können Sie dies nicht tun, es wird eine Fehlermeldung angezeigt:

mysql> create table foo (
  id int primary key auto_increment, 
  id2 int auto_increment
);
ERROR 1075 (42000): Incorrect table definition; 
there can be only one auto column and it must be defined as a key

In einigen anderen Datenbankmarken können Sie mehr als eine automatisch generierende Spalte in einer Tabelle definieren.


5
Was wäre der Sinn, wenn mehrere Spalten automatisch generiert würden?
Tarnay Kálmán

Ich habe keinen Anwendungsfall im Sinn, aber wenn es jemals einen Bedarf geben sollte, würden einige Datenbankmarken dies unterstützen und andere nicht. Das ist alles, was ich sage.
Bill Karwin

1
Hier ist ein Fall: In einer Auftragstabelle habe ich sowohl eine ID (automatisch inkrementiert) als auch eine externe ID (hashähnliche Zeichenfolgen). Beide sollten eindeutig sein, sodass man theoretisch sagen kann, dass beide "primär" sind. Natürlich kann dies mit einem sekundären eindeutigen Index durchgeführt werden, aber es ist immer noch ein legitimer Fall (IMHO)
Nir

2

Es ist nicht möglich, zwei Primärschlüssel gleichzeitig zu haben. Aber (vorausgesetzt, Sie haben den Fall nicht mit dem zusammengesetzten Schlüssel durcheinander gebracht), müssen Sie möglicherweise ein Attribut eindeutig machen.

CREATE t1(
c1 int NOT NULL,
c2 int NOT NULL UNIQUE,
...,
PRIMARY KEY (c1)
);

Beachten Sie jedoch, dass in einer relationalen Datenbank ein "Superschlüssel" eine Teilmenge von Attributen ist, die ein Tupel oder eine Zeile in einer Tabelle eindeutig identifizieren. Ein 'Schlüssel' ist ein 'Superschlüssel' mit einer zusätzlichen Eigenschaft, die das Entfernen eines Attributs aus dem Schlüssel dazu führt, dass dieser Schlüssel kein 'Superschlüssel' mehr ist (oder einfach ein 'Schlüssel' ein minimaler Superschlüssel ist). Wenn mehr Schlüssel vorhanden sind, sind alle Kandidatenschlüssel. Wir wählen einen der Kandidatenschlüssel als Primärschlüssel aus. Aus diesem Grund ist es ein Konflikt, über mehrere Primärschlüssel für eine Beziehung oder Tabelle zu sprechen.


Wikipedia hat keine Definition für "Schlüssel". Auch das "Entfernen eines Attributs aus dem Schlüssel, macht diesen Schlüssel nicht mehr zu einem" Superschlüssel "" bedeutete für mich nichts, da das Entfernen eines Attributs aus dem Superschlüssel immer noch ein Superschlüssel sein kann.
Manohar Reddy Poreddy

@ManoharReddyPoreddy Ja, in diesem Fall ist Ihr Attributsatz kein "Schlüssel", sondern ein "Superschlüssel". Was ich meine ist, wenn eine Menge von Attributen ein 'Schlüssel' sein soll, sollte die Menge minimal sein oder die Menge sollte eine zusätzliche Eigenschaft haben, dass das Entfernen eines Attributs aus der Menge die resultierende Menge nicht mehr zu einem 'Superschlüssel' macht.
Rusiru Adithya Samarasinghe

Sieht so aus, als ob Ihre eigentliche Bedeutung von 'Schlüssel' Candidate_key ( en.wikipedia.org/wiki/Candidate_key ) ist. Vielleicht sollte es so erwähnt werden.
Manohar Reddy Poreddy

@ManoharReddyPoreddy Ja, ich habe es bereits in meiner Antwort erwähnt. "Wenn es mehr Schlüssel gibt, sind alle Kandidatenschlüssel". Trotzdem danke für deine Bewertung.
Rusiru Adithya Samarasinghe

1. Wenn Sie erwähnen "Wenn es mehr Schlüssel gibt, sind alle Kandidatenschlüssel", ... meinen Sie etwas anderes / sonst sind sie keine Kandidatenschlüssel? ... 2. Wo ist der andere Teil? ... Sind wir überhaupt die gleiche Seite?
Manohar Reddy Poreddy

1

Ein Primärschlüssel ist der Schlüssel, der einen Datensatz eindeutig identifiziert und in allen Indizes verwendet wird. Deshalb können Sie nicht mehr als eine haben. Dies ist im Allgemeinen auch der Schlüssel, der beim Verknüpfen mit untergeordneten Tabellen verwendet wird. Dies ist jedoch keine Voraussetzung. Der eigentliche Zweck einer PK besteht darin, sicherzustellen, dass Sie einen Datensatz eindeutig identifizieren können, damit sich Datenänderungen auf den richtigen Datensatz auswirken und Indizes erstellt werden können.

Sie können jedoch mehrere Felder in einen Primärschlüssel (eine zusammengesetzte PK) einfügen. Dadurch werden Ihre Verknüpfungen langsamer (insbesondere wenn es sich um größere Felder vom Typ "Zeichenfolge" handelt) und Ihre Indizes werden größer. Möglicherweise müssen jedoch keine Verknüpfungen in einigen der untergeordneten Tabellen vorgenommen werden Fallbasis. Wenn Sie dies tun, ist jedes Feld selbst nicht eindeutig, aber die Kombination von ihnen ist. Wenn eines oder mehrere der Felder in einem zusammengesetzten Schlüssel ebenfalls eindeutig sein sollen, benötigen Sie einen eindeutigen Index dafür. Es ist jedoch wahrscheinlich, dass wenn ein Feld eindeutig ist, dies ein besserer Kandidat für die PK ist.

Jetzt haben Sie manchmal mehr als einen Kandidaten für die PK. In diesem Fall wählen Sie einen als PK oder verwenden einen Ersatzschlüssel (ich persönlich bevorzuge Ersatzschlüssel für diese Instanz). Und (dies ist wichtig!) Sie fügen jedem der Kandidatenschlüssel, die nicht als PK ausgewählt wurden, eindeutige Indizes hinzu. Wenn die Daten eindeutig sein müssen, benötigen sie einen eindeutigen Index, unabhängig davon, ob es sich um die PK handelt oder nicht. Dies ist ein Datenintegritätsproblem. (Beachten Sie, dass dies auch immer dann gilt, wenn Sie einen Ersatzschlüssel verwenden. Menschen haben Probleme mit Ersatzschlüsseln, weil sie vergessen, eindeutige Indizes für die Kandidatenschlüssel zu erstellen.)

Es gibt gelegentlich Fälle, in denen Sie mehr als einen Ersatzschlüssel benötigen (normalerweise die PK, wenn Sie diese haben). In diesem Fall möchten Sie nicht mehr PKs, sondern mehr Felder mit automatisch generierten Schlüsseln. Die meisten DBs erlauben dies nicht, aber es gibt Möglichkeiten, dies zu umgehen. Überlegen Sie zunächst, ob das zweite Feld basierend auf dem ersten automatisch generierten Schlüssel (z. B. Feld1 * -1) berechnet werden kann oder ob die Notwendigkeit eines zweiten automatisch generierten Schlüssels tatsächlich bedeutet, dass Sie eine verwandte Tabelle erstellen sollten. Verwandte Tabellen können in einer Eins-zu-Eins-Beziehung stehen. Sie würden dies erzwingen, indem Sie die PK aus der übergeordneten Tabelle zur untergeordneten Tabelle hinzufügen und dann das neue automatisch generierte Feld zur Tabelle und dann die für diese Tabelle geeigneten Felder hinzufügen. Wählen Sie dann einen der beiden Schlüssel als PK und setzen Sie einen eindeutigen Index auf den anderen (das automatisch generierte Feld muss keine PK sein). Stellen Sie sicher, dass Sie die FK zu dem Feld in der übergeordneten Tabelle hinzufügen. Wenn Sie keine zusätzlichen Felder für die untergeordnete Tabelle haben, müssen Sie im Allgemeinen untersuchen, warum Sie der Meinung sind, dass Sie zwei automatisch generierte Felder benötigen.


0

Gute technische Antworten wurden besser gegeben als ich. Ich kann nur zu diesem Thema hinzufügen:

Wenn Sie etwas wollen, das nicht erlaubt / akzeptabel ist, ist es ein guter Grund, einen Schritt zurückzutreten.

  1. Verstehe den Kern, warum es nicht akzeptabel ist.
  2. Weitere Informationen finden Sie in Dokumentation / Zeitschriftenartikeln / Web usw.
  3. Analysieren / überprüfen Sie das aktuelle Design und weisen Sie auf größere Mängel hin.
  4. Berücksichtigen und testen Sie jeden Schritt während des neuen Designs.
  5. Freuen Sie sich immer und versuchen Sie, eine adaptive Lösung zu erstellen.

Hoffe es wird jemandem helfen.


1
generischer (wenn auch nützlicher) Rat, keine Antwort auf die spezifische Frage.
Bradford Needham

-3

Ja, es ist in SQL möglich, aber wir können nicht mehr als einen Primärschlüssel in MsAccess festlegen. Dann weiß ich nichts über die anderen Datenbanken.

CREATE TABLE CHAPTER (
    BOOK_ISBN VARCHAR(50) NOT NULL,
    IDX INT NOT NULL,
    TITLE VARCHAR(100) NOT NULL,
    NUM_OF_PAGES INT,
    PRIMARY KEY (BOOK_ISBN, IDX)
);

Eine SQL-Tabelle kann nur eine PK haben.
Philipx
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.