Posso avere più chiavi primarie in una singola tabella?


Risposte:


559

Una tabella può avere una chiave primaria composita che è una chiave primaria composta da due o più colonne. Per esempio:

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

Aggiornamento: ecco un link con una descrizione più dettagliata delle chiavi primarie composite.


2
In questo esempio, ENTRAMBI userid e userdataid sono necessari per identificare / trovare una riga univoca. Non ero sicuro di quale fosse l'intenzione del PO, ma sono venuto qui per vedere se potevo identificare in modo univoco una riga con una di una serie di chiavi. Ad esempio, vorrei identificare un utente unico con un nome utente o un ID utente, senza bisogno di entrambi. Immagino che la risposta di RB di indici univoci farebbe il trucco lì.
Burrito,

1
@Benitok Come menzionato nella risposta di RB. , Puoi utilizzare gli indici unici per fare quello che stai cercando (una colonna unica e indicizzata indipendente da altre colonne uniche e indicizzate nella stessa tabella). Assicurati di consultare il tuo specifico aspetto del manuale di SQL per dettagli sull'esatta sintassi del linguaggio utilizzata.
AM

195

Puoi avere solo una chiave primaria, ma puoi avere più colonne nella tua chiave primaria.

Puoi anche avere indici univoci sulla tua tabella, che funzioneranno un po 'come una chiave primaria in quanto imporranno valori univoci e accelereranno l'interrogazione di tali valori.


39

Una tabella può avere più chiavi candidate. Ogni chiave candidata è una colonna o un insieme di colonne che sono UNICHE, prese insieme e anche NON NULL. Pertanto, specificare i valori per tutte le colonne di qualsiasi chiave candidata è sufficiente per determinare che esiste una riga che soddisfa i criteri o nessuna riga.

Le chiavi candidate sono un concetto fondamentale nel modello di dati relazionali.

È pratica comune, se più chiavi sono presenti in una tabella, designare una delle chiavi candidate come chiave primaria. È inoltre pratica comune fare in modo che qualsiasi chiave esterna della tabella faccia riferimento alla chiave primaria, piuttosto che a qualsiasi altra chiave candidata.

Raccomando queste pratiche, ma non c'è nulla nel modello relazionale che richiede la selezione di una chiave primaria tra le chiavi candidate.


5
Concordato. Tutte le chiavi sono uguali (nessuna è "primaria") nel modello logico. La scelta di quale chiave nell'implementazione fisica ottiene la designazione PRIMARY KEY dipende dall'arbitro e dipende dal fornitore / prodotto.
Onedayquando il

3
Direi che dipende dal progettista del database.
Walter Mitty,

Ho appena trovato un caso d'uso in cui è richiesto. Ho una tabella che verrà creata / gestita da Entity Framework, che per ora non supporta i vincoli compositi univoci di chiave non primaria. Tuttavia supporta chiavi primarie composite. I dati verranno inoltre collegati a un sistema di database remoto che non supporta affatto chiavi composite. Sono andato con la creazione di un PK composito in EF, ma ho anche aggiunto una colonna GUID non nullable che l'altro sistema può utilizzare per identificarsi in modo univoco.
Chris Nevill,

2
Chris, ho detto che il modello relazionale non richiede chiavi primarie. Non ho detto nulla sul fatto che alcuni strumenti potrebbero richiederli. Ma prendo il tuo punto.
Walter Mitty,

Penso che ci sia un requisito che il PK sia minimo, cioè che usi il minor numero di colonne per identificare in modo univoco ogni record.
gary,

14

Questa è la risposta sia alla domanda principale che alla domanda di @ Kalmi

Quale sarebbe il punto di avere più colonne auto-generate?

Questo codice di seguito ha una chiave primaria composita. Una delle sue colonne è auto-incrementata. Funzionerà solo in MyISAM. InnoDB genererà un errore " ERRORE 1075 (42000): definizione della tabella errata; può esserci solo una colonna automatica e deve essere definita come chiave ".

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
Funziona se si specifica prima la colonna auto-incrementante nella definizione della chiave primaria. (Forse è cambiato, l'ho appena provato in 5.6)
CTarczon

11

(Ho studiato molto questi)

Chiavi candidate : combinazione minima di colonne richiesta per identificare in modo univoco una riga della tabella.
Chiavi composte - 2 o più colonne.

  • In una tabella possono esistere più chiavi candidate .
    • CHIAVE primaria : solo una delle chiavi candidate da noi scelte
    • Chiavi alternative - Tutte le altre chiavi candidate
      • Sia la chiave primaria che le chiavi alternative possono essere chiavi composte

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

Come notato dagli altri, è possibile avere chiavi primarie a più colonne. Va notato tuttavia che se si dispone di alcune dipendenze funzionali che non sono introdotte da una chiave, è necessario considerare la normalizzazione della relazione.

Esempio:

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

Può esserci una dipendenza funzionale tra id -> name,email, street, zip_code and area Ma spesso a zip_codeè associata a areae quindi esiste una dipendenza funzionale interna tra zip_code -> area.

Quindi si può considerare di dividerlo in un'altra tabella:

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

In modo che sia coerente con la terza forma normale .


6

La chiave primaria è una notazione molto sfortunata, a causa della connotazione di "primaria" e dell'associazione subconscia di conseguenza con il modello logico. Evito quindi di usarlo. Invece mi riferisco alla chiave surrogata del modello fisico e alle chiavi naturali del modello logico.

È importante che il Modello logico per ogni Entità abbia almeno una serie di "attributi aziendali" che comprendono una Chiave per l'entità. Boyce, Codd, Date et al. Si riferiscono a questi nel modello relazionale come chiavi candidate. Quando poi costruiamo tabelle per queste entità, le loro chiavi candidate diventano chiavi naturali in quelle tabelle. È solo tramite quelle chiavi naturali che gli utenti sono in grado di identificare in modo univoco le righe nelle tabelle; come chiavi surrogate dovrebbero essere sempre nascoste agli utenti. Questo perché Surrogate Keys non ha significato commerciale.

Tuttavia, il modello fisico per le nostre tabelle sarà in molti casi inefficiente senza una chiave surrogata. Ricorda che le colonne non coperte per un indice non cluster possono essere trovate (in generale) solo attraverso una Ricerca chiave nell'indice cluster (ignora le tabelle implementate come heap per un momento). Quando le nostre chiavi naturali disponibili sono ampie, questa (1) amplia la larghezza dei nostri nodi foglia non cluster, aumentando i requisiti di archiviazione e gli accessi in lettura per ricerche e scansioni di quell'indice non cluster; e (2) riduce il fan-out dal nostro indice cluster aumentando l'altezza e la dimensione dell'indice, aumentando ancora le letture e i requisiti di archiviazione per i nostri indici cluster; e (3) aumenta i requisiti di cache per i nostri indici cluster. inseguendo altri indici e dati dalla cache.

È qui che una piccola chiave surrogata, designata come RDBMS come "chiave primaria" si rivela vantaggiosa. Se impostato come chiave di clustering, in modo da essere utilizzato per le ricerche di chiavi nell'indice cluster da indici non cluster e ricerche di chiavi esterne da tabelle correlate, tutti questi svantaggi scompaiono. I nostri fan-out degli indici cluster aumentano di nuovo per ridurre l'altezza e le dimensioni dell'indice cluster, ridurre il carico di cache per i nostri indici cluster, ridurre le letture quando si accede ai dati attraverso qualsiasi meccanismo (scansione dell'indice, ricerca indice, ricerca chiavi non cluster o ricerca chiave esterna) e ridurre i requisiti di archiviazione per gli indici cluster e non cluster delle nostre tabelle.

Si noti che questi vantaggi si verificano solo quando la chiave surrogata è sia piccola sia la chiave di clustering. Se viene utilizzato un GUID come chiave di clustering, la situazione sarà spesso peggiore rispetto a quando fosse stata utilizzata la chiave naturale più piccola disponibile. Se la tabella è organizzata come un heap, il RowID a 8 byte (heap) verrà utilizzato per le ricerche di chiavi, che è migliore di un GUID a 16 byte ma meno performante di un numero intero a 4 byte.

Se un GUID deve essere utilizzato a causa di vincoli aziendali, vale la pena cercare una chiave di clustering migliore. Se, ad esempio, è possibile un identificatore di sito di piccole dimensioni e un "numero di sequenza di siti" a 4 byte, tale progetto potrebbe fornire prestazioni migliori rispetto a un GUID come chiave sostitutiva.

Se le conseguenze di un heap (forse hash join) fanno sì che lo spazio di archiviazione preferito sia necessario, i costi di una chiave di clustering più ampia devono essere bilanciati nell'analisi del trade-off.

Considera questo esempio ::

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

dove la tupla " (P_Id, LastName) " richiede un vincolo di unicità e può essere un lungo LastName Unicode più un intero di 4 byte, sarebbe auspicabile (1) imporre dichiaratamente questo vincolo come " ADD CONSTRAINT pk_PersonID UNIQUE NONCLUSTERED (P_Id , LastName) "e (2) dichiarano separatamente una piccola chiave surrogata come" chiave primaria "di un indice cluster. Vale la pena notare che Anita probabilmente desidera solo aggiungere il LastName a questo vincolo per renderlo un campo coperto, che non è necessario in un indice cluster perché TUTTI i campi sono coperti da esso.

La capacità in SQL Server di designare una chiave primaria come non cluster è una sfortunata circostanza storica, a causa di una fusione del significato di "chiave naturale o candidata preferita" (dal modello logico) con il significato di "chiave di ricerca nella memoria" dal fisico Modello. La mia comprensione è che in origine SYBASE SQL Server utilizzava sempre un RowID a 4 byte, sia in un heap che in un indice cluster, come "chiave di ricerca in archivio" dal modello fisico.


3
Puoi per favore tradurre questo in inglese!
Jasir,

3

Alcune persone usano il termine "chiave primaria" per indicare esattamente una colonna intera che ottiene i suoi valori generati da un meccanismo automatico. Ad esempio AUTO_INCREMENTin MySQL o IDENTITYin Microsoft SQL Server. Stai usando la chiave primaria in questo senso?

In tal caso, la risposta dipende dalla marca del database in uso. In MySQL, non puoi farlo, ricevi un errore:

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 alcune altre marche di database, è possibile definire più di una colonna di generazione automatica in una tabella.


5
Quale sarebbe il punto di avere più colonne auto-generate?
Tarnay Kálmán,

Non ho in mente un caso d'uso, ma se mai ce ne fosse bisogno, alcune marche di database lo supporterebbero e altre no. Questo è tutto ciò che sto dicendo.
Bill Karwin,

1
Ecco un caso: in una tabella degli ordini, ho sia un ID (auto incrementato) sia un ID esterno (stringhe simili a hash), entrambi dovrebbero essere univoci, quindi teoricamente si potrebbe dire che sono entrambi "primari". ovviamente questo può essere fatto con un indice univoco secondario ma è comunque un caso legittimo (IMHO)
Nir

2

Non è possibile avere due chiavi primarie contemporaneamente. Ma (supponendo che non si sia incasinato il caso con una chiave composita), potrebbe essere necessario rendere unico un attributo.

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

Tuttavia, notare che nel database relazionale una "super chiave" è un sottoinsieme di attributi che identificano in modo univoco una tupla o una riga in una tabella. Una "chiave" è una "super chiave" che ha una proprietà aggiuntiva che rimuove qualsiasi attributo dalla chiave, non la rende più una "super chiave" (o semplicemente una "chiave" è una super chiave minima). Se ci sono più chiavi, tutte sono chiavi candidate. Selezioniamo una delle chiavi candidate come chiave primaria. Ecco perché parlare di più chiavi primarie per una relazione o tabella è un conflitto.


Wikipedia non ha una definizione di "chiave". Inoltre, la "rimozione di qualsiasi attributo dalla chiave non rende più tale chiave una" super chiave "" non significava nulla per me, poiché quando si rimuove un attributo dalla super chiave può essere comunque una super chiave.
Manohar Reddy Poreddy

@ManoharReddyPoreddy Sì, in tal caso, il tuo set di attributi non è una "chiave" ma una "super chiave". Ciò che intendo è se un set di attributi sia una 'chiave', il set dovrebbe essere minimo, o il set dovrebbe avere una proprietà aggiuntiva che la rimozione di qualsiasi attributo dal set rende il set risultante non più una 'super chiave'.
Rusiru Adithya Samarasinghe,

Sembra che il tuo vero significato di 'chiave' sia Candidate_key ( en.wikipedia.org/wiki/Candidate_key ), potrebbe essere che dovrebbe essere menzionato così.
Manohar Reddy Poreddy,

@ManoharReddyPoreddy Sì, l'ho già menzionato nella mia risposta. "Se ci sono più chiavi, tutte sono chiavi candidate". Comunque grazie per la tua recensione.
Rusiru Adithya Samarasinghe,

1. Quando dici "Se ci sono più chiavi, tutte sono chiavi candidate", ... Intendi altrimenti / altrimenti, non sono chiavi candidate? ... 2. Dov'è l'altra parte? ... Siamo tutti nella stessa pagina?
Manohar Reddy Poreddy

1

Una chiave primaria è la chiave che identifica in modo univoco un record e viene utilizzata in tutti gli indici. Ecco perché non puoi averne più di uno. In genere è anche la chiave utilizzata per unire le tabelle figlio ma non è un requisito. Il vero scopo di un PK è assicurarsi che qualcosa ti consenta di identificare in modo univoco un record in modo che le modifiche ai dati influiscano sul record corretto e che possano essere creati gli indici.

Tuttavia, è possibile inserire più campi in una chiave primaria (un PK composito). Ciò renderà i tuoi join più lenti (soprattutto se si tratta di campi di tipo stringa più grandi) e i tuoi indici più grandi, ma potrebbe rimuovere la necessità di eseguire join in alcune tabelle figlio, quindi per quanto riguarda le prestazioni e il design, prendilo in considerazione base del caso. Quando lo fai, ogni campo in sé non è unico, ma la combinazione di essi lo è. Se anche uno o più campi in una chiave composita devono essere univoci, è necessario un indice univoco su di essa. È probabile però che se un campo è unico, questo è un candidato migliore per il PK.

Ora, a volte, hai più di un candidato per il PK. In questo caso scegline uno come PK o usi una chiave surrogata (preferisco personalmente chiavi surrogate per questa istanza). E (questo è fondamentale!) Aggiungi indici univoci a ciascuna delle chiavi candidate che non sono state scelte come PK. Se i dati devono essere univoci, hanno bisogno di un indice univoco indipendentemente dal fatto che sia il PK o meno. Questo è un problema di integrità dei dati. (Nota che questo vale anche ogni volta che usi una chiave surrogata; le persone si mettono nei guai con le chiavi surrogate perché dimenticano di creare indici univoci sulle chiavi candidate.)

Ci sono volte in cui vuoi più di una chiave surrogata (che di solito sono le PK se le hai). In questo caso quello che vuoi non è più PK, sono più campi con chiavi autogenerate. La maggior parte dei DB non lo consente, ma ci sono modi per aggirarlo. In primo luogo, considerare se il secondo campo potrebbe essere calcolato in base alla prima chiave generata automaticamente (Field1 * -1 per esempio) o forse la necessità di una seconda chiave generata automaticamente significa che è necessario creare una tabella correlata. Le tabelle correlate possono essere in una relazione uno a uno. Lo faresti aggiungendo il PK dalla tabella padre alla tabella figlio e quindi aggiungendo il nuovo campo generato automaticamente alla tabella e quindi tutti i campi appropriati per questa tabella. Quindi scegli una delle due chiavi come PK e metti un indice univoco sull'altra (il campo generato automaticamente non deve essere un PK). E assicurati di aggiungere l'FK al campo che si trova nella tabella padre. In generale, se non si dispone di campi aggiuntivi per la tabella figlio, è necessario esaminare il motivo per cui si ritiene di aver bisogno di due campi generati automaticamente.


0

Buone risposte tecniche sono state fornite in un modo migliore di quello che posso fare. Sono solo possibile aggiungere a questo argomento:

Se vuoi qualcosa che non è permesso / accettabile, è una buona ragione per fare un passo indietro.

  1. Comprendi il nocciolo del perché non è accettabile.
  2. Scava di più nella documentazione / articoli di giornale / web e ecc.
  3. Analizzare / rivedere il progetto attuale e individuare i principali difetti.
  4. Considerare e testare ogni fase durante il nuovo design.
  5. Guarda sempre avanti e prova a creare una soluzione adattiva.

Spero che possa aiutare qualcuno.


1
consulenza generica (sebbene utile), non una risposta alla domanda specifica.
Bradford Needham,

-3

Sì, è possibile in SQL, ma non è possibile impostare più di una chiave primaria in MsAccess. Quindi, non conosco gli altri database.

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

Una tabella SQL può avere solo un PK.
Philipxy,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.