Pengaturan pengujian
Anda mengasumsikan nama kendala test_def_abc_id_fkey
, nama default yang dihasilkan dari pengaturan Anda di Postgres 11 atau lebih lama. Perlu dicatat, bahwa nama default telah ditingkatkan untuk Postgres 12, di mana pengaturan yang sama menghasilkan test_def_abc_id_abc_id2_fkey
. Catatan rilis untuk Postgres 12:
Lihat:
db<>fiddle di sini
Jadi mari kita gunakan nama eksplisit test_def_abc_fkey
untuk batasan FK untuk menghindari kebingungan:
CREATE TABLE test_abc (
pk int PRIMARY KEY
, id int NOT NULL
, id2 int NOT NULL
);
CREATE UNIQUE INDEX test_abc_ids ON test_abc(id,id2);
CREATE TABLE test_def (
id int PRIMARY KEY
, abc_id int
, abc_id2 int
, CONSTRAINT test_def_abc_fkey -- !
FOREIGN KEY (abc_id,abc_id2) REFERENCES test_abc(id,id2)
);
Dan berfungsi di Postgres 9.5 - Postgres 12.
Bahkan di Postgres 9.3.
(Saya telah mendapat kesan yang salah tentang batasan yang sebenarnya akan diperlukan.)
Jawab
Pengamatan Anda dari menanyakan skema informasi berlaku:
SELECT *
FROM information_schema.referential_constraints
WHERE constraint_name = 'test_def_abc_fkey'; -- unequivocal name
Kami mendapatkan satu baris, tetapi tiga bidang unique_constraint_catalog
, unique_constraint_schema
dan unique_constraint_name
adalah NULL
.
Penjelasannya tampaknya sederhana. Kolom-kolom itu menjelaskan, seperti yang dikatakan manual:
Tetapi tidak ada UNIQUE
batasan
, hanya UNIQUE
indeks
. Sebuah UNIQUE
kendala diimplementasikan menggunakan UNIQUE
indeks di Postgres. Batasan didefinisikan oleh standar SQL, indeks adalah detail implementasi. Ada perbedaan seperti yang Anda temukan. Terkait:
Tes yang sama dengan UNIQUE
yang sebenarnya batasan menampilkan data seperti yang diharapkan:
db<>fiddle di sini
Jadi ini sepertinya masuk akal. Terutama karena skema informasi juga didefinisikan oleh komite standar SQL dan indeks tidak standar, hanya kendala. (Tidak ada informasi indeks dalam tampilan skema informasi.)
Semua jelas? Tidak cukup.
Namun
Ada tampilan skema informasi lain key_column_usage
. Kolom terakhirnya digambarkan sebagai:
Tebal penekanan milikku. Di sini, posisi ordinal kolom di indeks tetap terdaftar:
SELECT *
FROM information_schema.key_column_usage
WHERE constraint_name = 'test_def_abc_fkey';
Lihat:
db<>fiddle di sini
Tampaknya tidak konsisten.
Yang lebih parah, manual
mengklaim bahwa PRIMARY KEY
actual yang sebenarnya atau UNIQUE
batasan akan diperlukan untuk pembuatan FOREIGN KEY
kendala:
Tampaknya menjadi bug dokumentasi ? Jika tidak ada yang bisa menunjukkan kesalahan saya di sini, saya akan mengajukan laporan bug.
Terkait:
Solusi
Di Postgres, katalog sistem adalah sumber kebenaran yang sebenarnya. Lihat:
Jadi Anda bisa menggunakan sesuatu seperti ini (seperti yang saya juga tambahkan di biola atas):
SELECT c.conname
, c.conrelid::regclass AS fk_table, k1.fk_columns
, c.confrelid::regclass AS ref_table, k2.ref_key_columns
FROM pg_catalog.pg_constraint c
LEFT JOIN LATERAL (
SELECT ARRAY (
SELECT a.attname
FROM pg_catalog.pg_attribute a
, unnest(c.conkey) WITH ORDINALITY AS k(attnum, ord)
WHERE a.attrelid = c.conrelid
AND a.attnum = k.attnum
ORDER BY k.ord
) AS fk_columns
) k1 ON true
LEFT JOIN LATERAL (
SELECT ARRAY (
SELECT a.attname
FROM pg_catalog.pg_attribute a
, unnest(c.confkey) WITH ORDINALITY AS k(attnum, ord)
WHERE a.attrelid = c.confrelid
AND a.attnum = k.attnum
ORDER BY k.ord
) AS ref_key_columns
) k2 ON true
WHERE conname = 'test_def_abc_fkey';
Pengembalian:
conname | fk_table | fk_columns | ref_table | ref_key_columns :---------------- | :------- | :--------------- | :-------- | :-------------- test_def_abc_fkey | test_def | {abc_id,abc_id2} | test_abc | {id,id2}
Terkait:
- Temukan nama tabel yang dirujuk menggunakan tabel, bidang, dan nama skema
- Temukan bidang yang dirujuk( s) batasan kunci asing
- Bagaimana cara menemukan tabel yang mereferensikan baris tertentu melalui kunci asing?