Co powoduje BŁĄD: nie ma unikalnego ograniczenia pasującego do danych kluczy dla tabeli, do której się odwołuje?

154

Poniższa przykładowa struktura tabeli daje BŁĄD: nie ma unikalnego ograniczenia pasującego do podanych kluczy dla tabeli, do której się odwołujemy, a przyglądając się temu od jakiegoś czasu nie mogę zrozumieć, dlaczego ten błąd pojawia się w tej sytuacji.

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;

Uruchomienie powyższego kodu daje następujący błąd, który nie ma dla mnie sensu, ktoś może wyjaśnić, dlaczego ten błąd się pojawia. Używam 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
ams
źródło

Odpowiedzi:

188

Dzieje się tak, ponieważ namekolumna w bartabeli nie ma ograniczenia UNIQUE .

Więc wyobraź sobie, że masz 2 wiersze w bartabeli, które zawierają nazwę, 'ams'i wstawiasz wiersz bazz 'ams'włączonym bar_fk, do którego wiersza barbędzie się odnosił, ponieważ są dwa pasujące wiersze?

Diego
źródło
1
doskonałe, krótkie i precyzyjne oraz łatwe do złapania wyjaśnienie!
Alex
79

W postgresql wszystkie klucze obce muszą odnosić się do unikalnego klucza w tabeli nadrzędnej, więc w bartabeli musisz mieć unique (name)indeks.

Zobacz także http://www.postgresql.org/docs/9.1/static/ddl-constraints.html#DDL-CONSTRAINTS-FK, a konkretnie:

Na koniec powinniśmy wspomnieć, że klucz obcy musi odwoływać się do kolumn, które są kluczem podstawowym lub tworzą unikalne ograniczenie.

Podkreśl moje.

Matteo Tassinari
źródło
21
dlaczego zadeklarowana PK nie jest uważana za unikalne ograniczenie? to nie jest tak, że możesz mieć nieuniknione PK ...
amfibie,
2
Musi być unikalna w tabeli, na którą „wskazuje”, ponieważ jeśli tak nie jest, silnik bazy danych nie będzie miał możliwości ustalenia, do którego wiersza się odwołujesz.
Matteo Tassinari,
Klucze złożone? @amphibient
Charming Robot
1
Myślę, że posiadanie unikalnego klucza w wymienionej kolumnie w tabeli nadrzędnej nie jest wymagane tylko w postgresql, ale także w innych RDBMS, takich jak Oracle, SQL Server itp.
Mufachir Hossain
2
Zwróć uwagę, że odpowiedź jest prawdziwa również dla złożonych kluczy obcych, w przypadku których w tabeli nadrzędnej wymagane jest złożone ograniczenie unikalności lub klucz podstawowy.
Ninjakannon
8

kiedy wykonujesz UNIQUEograniczenie na poziomie tabeli, tak jak to zrobiłeś, to to, co definiujesz, przypomina nieco złożony klucz podstawowy, zobacz ograniczenia ddl , tutaj jest wyciąg

"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."

oznacza to, że każde pole może prawdopodobnie mieć nieunikalną wartość, pod warunkiem, że kombinacja jest unikalna i nie pasuje do ograniczenia klucza obcego.

najprawdopodobniej chcesz, aby ograniczenie znajdowało się na poziomie kolumny. Zamiast tego zdefiniuj je jako ograniczenia na poziomie tabeli, „dołącz” UNIQUEna końcu definicji kolumny, np. name VARCHAR(60) NOT NULL UNIQUEokreśl lub określ indywidualne ograniczenia na poziomie tabeli dla każdego pola.

TI
źródło
Ograniczenie na poziomie kolumny w mojej sytuacji nie zadziała. Naprawdę powinienem zdefiniować złożony klucz podstawowy, ale wycofałem się z tego, ponieważ mapowanie go do JPA jest trochę uciążliwe :)
am.
6

Powinieneś mieć kolumnę z nazwą jako unikalne ograniczenie. tutaj są 3 linie kodu, aby zmienić Twoje problemy

  1. Najpierw znajdź ograniczenia klucza podstawowego, wpisując ten kod

    \d table_name

    jesteś pokazany w ten sposób na dole "some_constraint" PRIMARY KEY, btree (column)

  2. Porzuć ograniczenie:

    ALTER TABLE table_name DROP CONSTRAINT some_constraint
  3. Dodaj nową kolumnę klucza podstawowego z istniejącą:

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

To wszystko.

Hari Bharathi
źródło