Kann ich mehrere Primärschlüssel in einer einzigen Tabelle haben?
Kann ich mehrere Primärschlüssel in einer einzigen Tabelle haben?
Antworten:
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.
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.
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.
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 |
+--------+----+---------+
(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.
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
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_code
ist jedoch a mit a verbunden, area
und 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 .
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.
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_INCREMENT
in MySQL oder IDENTITY
in 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.
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.
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.
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.
Hoffe es wird jemandem helfen.
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)
);