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.