Cosa sta causando ERRORE: non esiste un vincolo univoco che corrisponda a determinate chiavi per la tabella referenziata?


155

Di seguito la struttura della tabella di esempio fornisce un ERRORE: non esiste un vincolo univoco per la corrispondenza delle chiavi fornite per la tabella di riferimento e dopo averlo fissato per un po ', non riesco a capire perché questo errore si presenti in questa situazione.

BEGIN;

CREATE TABLE foo (
    name                VARCHAR(256) PRIMARY KEY
);

CREATE TABLE bar(
    pkey        SERIAL PRIMARY KEY,
    foo_fk      VARCHAR(256) NOT NULL REFERENCES foo(name), 
    name        VARCHAR(256) NOT NULL, 
    UNIQUE (foo_fk,name)
);

CREATE TABLE baz(   
    pkey            SERIAL PRIMARY KEY,
    bar_fk          VARCHAR(256) NOT NULL REFERENCES bar(name),
    name            VARCHAR(256)
);

COMMIT;

L'esecuzione del codice sopra riportato dà il seguente errore, che non ha senso per me, qualcuno può spiegare perché si verifica questo errore. Sto usando Postgres 9.1

NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "foo_pkey" for table "foo"
NOTICE:  CREATE TABLE will create implicit sequence "bar_pkey_seq" for serial column "bar.pkey"
NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "bar_pkey" for table "bar"
NOTICE:  CREATE TABLE / UNIQUE will create implicit index "bar_foo_fk_name_key" for table "bar"
NOTICE:  CREATE TABLE will create implicit sequence "baz_pkey_seq" for serial column "baz.pkey"
NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "baz_pkey" for table "baz"
ERROR:  there is no unique constraint matching given keys for referenced table "bar"


********** Error **********

ERROR: there is no unique constraint matching given keys for referenced table "bar"
SQL state: 42830

Risposte:


189

È perché la namecolonna nella bartabella non ha il vincolo UNIQUE .

Immagina quindi di avere 2 righe sulla bartabella che contengono il nome 'ams'e di inserire una riga bazcon 'ams'on bar_fk, su quale riga barfarebbe riferimento poiché ci sono due righe corrispondenti?


1
spiegazione perfetta breve, precisa e facile da catturare!
Alex,

79

In postgresql tutte le chiavi esterne devono fare riferimento a una chiave univoca nella tabella padre, quindi nella tua bartabella devi avere un unique (name)indice.

Vedi anche http://www.postgresql.org/docs/9.1/static/ddl-constraints.html#DDL-CONSTRAINTS-FK e in particolare:

Infine, dovremmo menzionare che una chiave esterna deve fare riferimento a colonne che sono una chiave primaria o formano un vincolo univoco.

Enfasi mia.


21
perché il PK dichiarato non è considerato un vincolo unico? non è che tu possa avere un PK non originale ...
anfibio

2
Deve essere univoco nella tabella a cui "punta", poiché in caso contrario il motore di database non avrà modo di sapere a quale riga si sta effettivamente facendo riferimento.
Matteo Tassinari,

Tasti compositi? @amphibient
Charming Robot il

1
Penso che avere una chiave univoca sulla colonna di riferimento nella tabella padre non sia richiesto solo in postgresql ma anche in altri RDBMS come oracle, sql server ecc.
Mufachir Hossain,

2
Si noti che la risposta è vera anche per le chiavi esterne composite, in cui è richiesto un vincolo univoco composito o chiave primaria nella tabella padre.
Ninjakannon,

8

quando fai UNIQUEcome un vincolo a livello di tabella come hai fatto allora ciò che definisci è un po 'come una chiave primaria composita vedi i vincoli ddl , ecco un estratto

"This specifies that the *combination* of values in the indicated columns is unique across the whole table, though any one of the columns need not be (and ordinarily isn't) unique."

ciò significa che entrambi i campi potrebbero avere un valore non univoco, purché la combinazione sia unica e ciò non corrisponda al vincolo della chiave esterna.

molto probabilmente vuoi che il vincolo sia a livello di colonna. quindi piuttosto definirli come vincoli a livello di tabella, 'aggiungere' UNIQUEalla fine della definizione di colonna come name VARCHAR(60) NOT NULL UNIQUEo specificare vincoli a livello di tabella individuali per ciascun campo.


Il vincolo a livello di colonna nella mia situazione non funzionerà Dovrei davvero definire una chiave primaria composta, ma mi sono allontanato da essa perché mapparla su JPA è un po 'una seccatura :)
ams

6

Dovresti avere la colonna del nome come vincolo univoco. ecco un 3 righe di codice per cambiare i tuoi problemi

  1. Per prima cosa scopri i vincoli della chiave primaria digitando questo codice

    \d table_name

    ti viene mostrato così in fondo "some_constraint" PRIMARY KEY, btree (column)

  2. Elimina il vincolo:

    ALTER TABLE table_name DROP CONSTRAINT some_constraint
  3. Aggiungi una nuova colonna chiave primaria con una esistente:

    ALTER TABLE table_name ADD CONSTRAINT some_constraint PRIMARY KEY(COLUMN_NAME1,COLUMN_NAME2);

È tutto.

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.