Apa yang menyebabkan ERROR: tidak ada batasan unik yang diberikan kunci untuk tabel referensi?

155

Di bawah ini contoh struktur tabel memberikan ERROR: tidak ada batasan unik yang diberikan kunci untuk tabel yang direferensikan, dan setelah menatapnya untuk sementara waktu sekarang saya tidak tahu mengapa kesalahan ini muncul dalam situasi ini.

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;

Menjalankan kode di atas memberikan kesalahan berikut, yang tidak masuk akal bagi saya, adakah yang bisa menjelaskan mengapa kesalahan ini muncul. Saya menggunakan 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
am
sumber

Jawaban:

189

Itu karena namekolom di atas barmeja tidak memiliki batasan UNIK .

Jadi bayangkan Anda memiliki 2 baris pada bartabel yang berisi nama 'ams'dan Anda menyisipkan baris bazdengan 'ams'pada bar_fk, baris mana yang barakan merujuk karena ada dua baris yang cocok?

Diego
sumber
1
penjelasan singkat dan tepat dan mudah ditangkap sempurna!
Alex
79

Dalam postgresql semua kunci asing harus merujuk kunci unik di tabel induk, jadi di bartabel Anda, Anda harus memiliki unique (name)indeks.

Lihat juga http://www.postgresql.org/docs/9.1/static/ddl-constraints.html#DDL-CONSTRAINTS-FK dan secara khusus:

Akhirnya, kita harus menyebutkan bahwa kunci asing harus mereferensikan kolom yang merupakan kunci utama atau membentuk batasan unik.

Tekankan milikku.

Matteo Tassinari
sumber
21
mengapa PK yang dinyatakan tidak dianggap sebagai kendala unik? tidak seperti Anda dapat memiliki PK yang tidak unik ...
amfibi
2
Itu harus unik pada tabel "menunjuk ke", karena jika tidak, mesin database tidak akan memiliki cara untuk mengetahui baris mana yang sebenarnya Anda maksud.
Matteo Tassinari
Kunci komposit? @amphibient
Charming Robot
1
Saya pikir memiliki kunci unik pada kolom yang direferensikan pada tabel induk tidak diperlukan di postgresql saja tetapi juga RDBMS lainnya juga seperti oracle, sql server dll.
Mufachir Hossain
2
Perhatikan bahwa jawabannya benar juga untuk kunci asing komposit, di mana batasan unik komposit atau kunci primer diperlukan pada tabel induk.
Ninjakannon
8

ketika Anda melakukan UNIQUEsebagai batasan level tabel seperti yang telah Anda lakukan maka apa yang Anda mendefinisikan adalah sedikit seperti kunci primer komposit melihat kendala ddl , di sini adalah ekstrak

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

ini berarti bahwa salah satu bidang dapat memiliki nilai yang tidak unik asalkan kombinasi tersebut unik dan ini tidak cocok dengan batasan kunci asing Anda.

kemungkinan besar Anda ingin kendala berada di level kolom. jadi alih-alih mendefinisikannya sebagai batasan level tabel, 'tambahkan' UNIQUEke akhir definisi kolom seperti name VARCHAR(60) NOT NULL UNIQUEatau tentukan batasan level tabel indivdual untuk setiap bidang.

TI
sumber
Kendala tingkat kolom dalam situasi saya tidak akan berfungsi. Saya benar-benar harus mendefinisikan kunci primer majemuk, tetapi saya mundur darinya karena memetakannya ke JPA sedikit
menyusahkan
6

Anda harus memiliki kolom nama sebagai batasan unik. di sini ada 3 baris kode untuk mengubah masalah Anda

  1. Pertama cari tahu batasan kunci utama dengan mengetik kode ini

    \d table_name

    Anda ditampilkan seperti ini di bagian bawah "some_constraint" PRIMARY KEY, btree (column)

  2. Jatuhkan batasan:

    ALTER TABLE table_name DROP CONSTRAINT some_constraint
  3. Tambahkan kolom kunci utama baru dengan yang sudah ada:

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

Itu saja.

Hari Bharathi
sumber