2008-10-20 13 views

Antwort

158

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 für Ihre Tabelle haben, die ein wenig wie ein Primärschlüssel funktioniert, da sie eindeutige Werte erzwingen und die Abfrage dieser Werte beschleunigen.

+10

+1 für die Erwähnung Unique Indexe –

441

Eine Tabelle kann einen zusammengesetzten Primärschlüssel haben, der ein Primärschlüssel aus zwei oder mehr Spalten ist. Zum Beispiel:

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

Update:Here is a link mit einer detaillierteren Beschreibung des zusammengesetzten Primärschlüssels.

+14

+1 für den Link, Adam. Hat mir definitiv sehr geholfen. Vielen Dank. –

+0

In diesem Beispiel werden BEIDE userid und userdataid benötigt, um eine eindeutige Zeile zu identifizieren. Nicht sicher, was die Absicht des OP war, aber ich kam hierher, um zu sehen, ob ich eine Reihe mit einem einer Reihe von Schlüsseln eindeutig identifizieren konnte. Zum Beispiel möchte ich einen eindeutigen Benutzer mit einem Benutzernamen ODER einer Benutzer-ID identifizieren, ohne beide zu benötigen. Ich denke, dass die Antwort von RB auf eindeutige Indizes dort den Trick bringen würde. – Benitok

+0

@Benitok Wie in RBs [Antwort] (https://Stackoverflow.com/a/217948/206552) erwähnt, können Sie Unique Indexes verwenden, um das zu tun, was Sie suchen (eine eindeutige, indizierte Spalte, die unabhängig von anderen ist eindeutige, indizierte Spalten in derselben Tabelle). Weitere Informationen zur genauen verwendeten Sprachsyntax finden Sie im Handbuch zu SQL. – 4AM

2

Einige Leute verwenden den Begriff "Primärschlüssel", um genau eine Ganzzahlspalte zu meinen, die seine Werte durch einen automatischen Mechanismus erzeugt. Zum Beispiel AUTO_INCREMENT in MySQL oder IDENTITY in Microsoft SQL Server. Verwenden Sie Primärschlüssel in diesem Sinne?

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

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 Marken der Datenbank, sind Sie in der Lage mehr als eine Auto-Erzeugungs Spalte in einer Tabelle zu definieren.

+5

Was wäre der Punkt mit mehreren automatisch generierenden Spalten? –

+0

Ich habe keinen Anwendungsfall im Sinn, aber wenn es jemals einen Bedarf gab, würden einige Marken der Datenbank dies unterstützen und andere nicht. Das ist alles, was ich sage. –

31

Eine Tabelle kann mehrere Kandidatenschlüssel haben. Jeder Kandidatenschlüssel ist eine Spalte oder Gruppe von Spalten, die zusammen UNIQUE sind, und auch NOT NULL. Daher reicht die Angabe von Werten für alle Spalten eines beliebigen Kandidatenschlüssels aus, um zu bestimmen, 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 festzulegen. Es ist auch üblich, dass alle Fremdschlüssel der Tabelle den Primärschlüssel referenzieren, und nicht irgendeinen anderen möglichen Schlüssel.

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

+4

Einverstanden. Alle Schlüssel sind im logischen Modell gleich (keine ist 'primär'). Die Wahl, welcher Schlüssel in der physischen Implementierung den PRIMARY KEY-Namen erhält, ist arbitray- und vendor/product-abhängig. – onedaywhen

+2

Ich würde sagen, dass es Datenbank-Designer abhängig ist. –

+0

Ich bin gerade auf einen Anwendungsfall gestoßen, in dem dies erforderlich ist. Ich habe eine Tabelle, die von Entity Framework erstellt/verwaltet wird. Soweit ich feststellen kann, werden derzeit keine nicht zusammengesetzten, nicht primären Kombinationsbedingungen unterstützt. Es unterstützt jedoch zusammengesetzte Primärschlüssel. Die Daten werden auch mit einem entfernten Datenbanksystem verknüpft, das keine zusammengesetzten Schlüssel unterstützt. Ich bin mit der Erstellung einer Composite PK in EF gegangen, habe aber auch eine GUID-Spalte hinzugefügt, auf die das andere System eindeutig zugreifen kann. –

-2

Ja, es ist in SQL möglich, , aber wir können nicht mehr als einen Primärschlüssel in MsAccess festlegen. Dann weiß ich nicht ü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) 
); 
12

Dies ist die Antwort sowohl für die Hauptfrage und für @ Kalmi Frage von

What would be the point of having multiple auto-generating columns?

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

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

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

6

Wie von den anderen erwähnt, ist es möglich, mehrspaltige Primärschlüssel zu haben. Es sollte jedoch beachtet werden, dass, wenn Sie einige functional dependencies haben, die nicht durch einen Schlüssel eingeführt werden, sollten Sie normalizing Ihre Beziehung betrachten.

Beispiel:

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

Es kann eine funktionale Abhängigkeit zwischen id -> name,email, street, zip_code and area sein, aber oft ein zip_code mit einem area verbunden ist und somit gibt es eine interne Funktions dependecy zwischen zip_code -> area.

So kann man prüfen, sie in einer anderen Tabelle aufteilen:

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

also, dass sie mit den third normal form konsistent ist.

1

Gute technische Antworten wurden in besserer Weise gegeben, als ich tun kann. Ich kann nur zu diesem Thema hinzufügen:

Wenn Sie etwas, das nicht erlaubt/akzeptabel wollen, ist es ein guter Grund, Schritt zurück zu nehmen.

  1. Verstehen Sie den Kern, warum es nicht akzeptabel ist.
  2. Dig mehr in der Dokumentation/Zeitschriftenartikel/Web und etc.
  3. Analysieren/überprüfen aktuelle Design und zeigen große Fehler.
  4. Betrachten und testen Sie jeden Schritt während des neuen Designs.
  5. Immer nach vorne schauen und versuchen, adaptive Lösung zu erstellen.

Ich hoffe, es wird jemandem helfen.

+1

generische (wenn auch nützliche) Beratung, keine Antwort auf die konkrete Frage. –

2

Ein Primärschlüssel ist der Schlüssel, der einen Datensatz eindeutig identifiziert und in allen Indizes verwendet wird. Deshalb können Sie nicht mehrere haben. Es ist im Allgemeinen auch der Schlüssel, der beim Verbinden mit untergeordneten Tabellen verwendet wird, dies ist jedoch keine Voraussetzung. Der eigentliche Zweck eines PK besteht darin, sicherzustellen, dass Sie mit einem Element einen Datensatz eindeutig identifizieren können, sodass 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 Joins langsamer (insbesondere wenn es sich um größere Felder vom Stringtyp handelt) und Ihre Indizes sind größer, aber die Joins in einigen der untergeordneten Tabellen können entfernt werden, was Leistung und Design angeht 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 sollten, benötigen Sie einen eindeutigen Index. Es ist jedoch wahrscheinlich, dass, wenn ein Feld einzigartig 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 (das ist kritisch!) 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ötigt sie einen eindeutigen Index, unabhängig davon, ob es sich um den PK handelt oder nicht. Dies ist ein Problem der Datenintegrität. (Beachten Sie, dass dies auch immer dann gilt, wenn Sie einen Surrogatschlüssel verwenden. Die Personen geraten in Schwierigkeiten mit Ersatzschlüsseln, weil sie vergessen, eindeutige Indizes für die Kandidatenschlüssel zu erstellen.)

Gelegentlich möchten Sie mehrere Ersatzschlüssel (die sind in der Regel die PK, wenn Sie sie haben).In diesem Fall ist das, was Sie wollen, nicht mehr PKs, es sind mehr Felder mit automatisch generierten Schlüsseln. Die meisten DBs erlauben dies nicht, aber es gibt Möglichkeiten, um es zu umgehen. Überlegen Sie zuerst, ob das zweite Feld auf der Grundlage des ersten automatisch generierten Schlüssels (z. B. Field1 * -1) berechnet werden könnte, oder dass die Notwendigkeit eines zweiten automatisch generierten Schlüssels wirklich 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 der untergeordneten Tabelle das PK aus der übergeordneten Tabelle hinzufügen und dann das neue automatisch generierte Feld zur Tabelle hinzufügen und dann die Felder, die für diese Tabelle geeignet sind. Wählen Sie dann einen der beiden Schlüssel als PK und legen Sie einen eindeutigen Index auf den anderen (das automatisch generierte Feld muss kein PK sein). Und stellen Sie sicher, dass der FK dem Feld in der übergeordneten Tabelle hinzugefügt wird. Wenn Sie keine zusätzlichen Felder für die untergeordnete Tabelle haben, müssen Sie im Allgemeinen untersuchen, warum Sie zwei automatisch generierte Felder benötigen.

+14

Der erste Absatz hier ist einfach völlig falsch. – sqlvogel

7

Primärschlüssel ist sehr unglückliche Notation, wegen der Konnotation von "Primary" und der unbewussten Assoziation in Folge mit dem logischen Modell. Ich vermeide es daher, es zu benutzen. Stattdessen verweise ich auf den Ersatzschlüssel des physischen Modells und den/die natürlichen Schlüssel des logischen Modells.

Es ist wichtig, dass das logische Modell für jede Entität mindestens eine Gruppe von "Geschäftsattributen" enthält, die einen Schlüssel für die Entität enthalten. Boyce, Codd, Date et al beziehen sich im Relationalen Modell auf diese als Kandidatenschlüssel. Wenn wir dann Tabellen für diese Entitäten erstellen, werden ihre Kandidatenschlüssel zu Natural Keys in diesen Tabellen. Nur durch diese Natural Keys können Benutzer Zeilen in den Tabellen eindeutig identifizieren. als Ersatzschlüssel sollten immer vor Benutzern verborgen werden. Dies liegt daran, dass Surrogate Keys keine geschäftliche Bedeutung haben.

Allerdings wird das physikalische Modell für unsere Tabellen in vielen Fällen ohne einen Ersatzschlüssel ineffizient sein. Es sei daran erinnert, dass nicht abgedeckte Spalten für einen nicht gruppierten Index (im Allgemeinen) nur über eine Schlüsselsuche in den gruppierten Index gefunden werden können (ignorieren Sie die für einen Moment als Heaps implementierten Tabellen). Wenn unsere verfügbaren Natural Key (s) weit sind, erweitert dies (1) die Breite unserer nicht geclusterten Blattknoten, erhöht die Speicheranforderungen und Lesezugriffe für Suchvorgänge und Scans dieses nicht geclusterten Indexes; und (2) reduziert Fan-Out von unserem Clustered Index, der die Indexhöhe und die Indexgröße erhöht, was wiederum die Lese- und Speicheranforderungen für unsere Clustered-Indizes erhöht; und (3) erhöht die Cache-Anforderungen für unsere gruppierten Indizes. jagen andere Indizes und Daten aus dem Cache.

Hier erweist sich ein kleiner Ersatzschlüssel, der dem RDBMS als "Primärschlüssel" zugeordnet ist, als vorteilhaft. Wenn sie als Clusterschlüssel festgelegt sind, um sie für Schlüsselsuchen in den gruppierten Index von nicht gruppierten Indizes und Fremdschlüsselsuchen aus verwandten Tabellen zu verwenden, verschwinden alle diese Nachteile. Unsere Fan-Outs für Cluster-Indizes werden erneut erhöht, um Clustered-Index-Höhe und -Größe zu reduzieren, die Cache-Belastung für unsere Clustered-Indizes zu verringern und Lesevorgänge beim Zugriff auf Daten über einen beliebigen Mechanismus zu reduzieren (ob Indexsuche, Indexsuche, nicht gruppierte Schlüsselsuche oder Fremdschlüsselsuche). und verringern Speicheranforderungen für Clustered und Nonclustered-Indizes unserer Tabellen.

Beachten Sie, dass diese Vorteile nur auftreten, wenn der Ersatzschlüssel klein und der Clusterschlüssel ist. Wenn eine GUID als Clustering-Schlüssel verwendet wird, ist die Situation oft schlechter, als wenn der kleinste verfügbare Natural Key verwendet worden wäre. Wenn die Tabelle als Heapspeicher organisiert ist, wird die 8-Byte-RowID (Heap) für Schlüsselsuchen 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, ist die Suche nach einem besseren Clusterschlüssel sinnvoll. Wenn beispielsweise eine kleine Site-Kennung und eine 4-Byte-Site-Sequenznummer möglich ist, kann dieses Design eine bessere Leistung als eine GUID als Ersatzschlüssel bieten.

Wenn die Konsequenzen eines Heaps (Hash-Join vielleicht) den bevorzugten Speicher ausmachen, dann müssen die Kosten eines breiteren Clustering-Schlüssels in die Trade-Off-Analyse ausgeglichen werden.

Betrachten dieses Beispiel ::

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

wo das Tupel "(P_ID, Nachname)" eine Eindeutigkeitsbedingung erfordert, und kann einen langwierigen Unicode Namen sowie eine 4-Byte-Ganzzahl sein, es wäre, wünschenswert, um (1) diese Beschränkung als "HINZUFÜGEN CONSTRAINT pk_PersonID UNIQUE NONCLUSTERED (P_Id, Nachname)" deklarativ durchzusetzen und (2) separat einen kleinen Ersatzschlüssel zu dem "Primärschlüssel" eines gruppierten Indexes zu erklären. Es ist erwähnenswert, dass Anita möglicherweise nur den Nachnamen zu dieser Einschränkung hinzufügen möchte, um dies zu einem abgedeckten Feld zu machen, was in einem gruppierten Index unnötig ist, da ALLE Felder von ihm bedeckt sind. Die Fähigkeit in SQL Server, einen Primärschlüssel als nicht gruppiert zu kennzeichnen, ist ein unglücklicher historischer Umstand, weil die Bedeutung "bevorzugter natürlicher oder Kandidatschlüssel" (aus dem logischen Modell) mit der Bedeutung "Nachschlagschlüssel im Speicher" zusammenfasst ist "aus dem physikalischen Modell. Mein Verständnis ist, dass ursprünglich SYBASE SQL Server immer eine 4-Byte-RowID, ob in einem Heap oder einem gruppierten Index, als "Suchschlüssel im Speicher" aus dem physikalischen Modell verwendet.

+2

Kannst du das bitte auf Englisch übersetzen? – Jasir

1

Es ist nicht möglich, zwei Primärschlüssel gleichzeitig zu verwenden. Aber (unter der Annahme, dass Sie den Fall nicht mit dem zusammengesetzten Schlüssel durcheinander gebracht haben), könnte es sein, dass Sie ein Attribut eindeutig machen müssen.

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

jedoch beachten, dass in relationaler Datenbank ein ‚Super-key‘ eine Untergruppe von Attributen ist, die eindeutig ein Tupel identifizieren oder in einer Tabellenzeile. Ein "Schlüssel" ist ein "Super-Schlüssel", der eine zusätzliche Eigenschaft aufweist, durch die jedes Attribut aus dem Schlüssel entfernt wird, so dass dieser Schlüssel kein "Super-Schlüssel" mehr ist (oder einfach ein "Schlüssel" ein minimaler Super-Schlüssel ist). Wenn es mehr Schlüssel gibt, sind alle Kandidatenschlüssel. Wir wählen einen der Kandidatenschlüssel als Primärschlüssel aus. Das ist der Grund, warum das Sprechen über mehrere Primärschlüssel für eine einzelne Relation oder Tabelle ein Konflikt ist.

Verwandte Themen