Mengapa kunci asing komposit memerlukan batasan unik yang terpisah?

10

Berikut adalah tabel sederhana tempat catatan dapat merujuk catatan induk di tabel yang sama:

CREATE TABLE foo (
    id         SERIAL  PRIMARY KEY,
    parent_id  INT     NULL,
    num        INT     NOT NULL,
    txt        TEXT    NULL,
    FOREIGN KEY (parent_id) REFERENCES foo(id)
);

Dengan persyaratan tambahan bahwa salah satu nilai bidang lainnya ( num) harus identik antara catatan induk dan anak, saya pikir kunci asing gabungan harus melakukan trik. Saya mengubah baris terakhir menjadi

    FOREIGN KEY (parent_id, num) REFERENCES foo(id, num)

dan mendapat ERROR: tidak ada batasan unik yang diberikan kunci untuk tabel referensi "foo" .

Saya dapat dengan mudah menambahkan batasan ini, tetapi saya tidak mengerti mengapa itu perlu, ketika salah satu kolom yang direferensikan ( id) sudah dijamin unik? Cara saya melihatnya, kendala baru akan menjadi berlebihan.

Zilk
sumber

Jawaban:

11

Ini adalah batasan dari DBMS - semuanya sejauh yang saya tahu. Dan tidak hanya saat menambahkan kolom tetapi juga saat menyusun ulang kolom. Jika kita memiliki UNIQUEbatasan pada (a1, a2), kita tidak dapat menambahkan FOREIGN KEYitu REFERENCES (a2, a1)kecuali ada batasan unik pada apa (a2, a1)yang pada dasarnya berlebihan.

Tidak akan terlalu sulit untuk menambahkan ini sebagai fitur:

Ketika ada UNIQUEkendala pada (a), maka setiap (a, b, c, ..., z)atau (b,c, ...a, ...z)kombinasi juga dijamin UNIQUE.

atau generalisasi:

Ketika ada UNIQUEkendala (a1, a2, ..., aN), maka semua (a1, a2, ..., aN, b1, b2, ..., bM)kombinasi atau pengaturan ulang juga dijamin UNIQUE.

Tampaknya itu belum diminta atau belum dianggap prioritas cukup tinggi untuk diimplementasikan.

Anda selalu dapat membuat permintaan - di saluran masing-masing - untuk fitur yang akan diterapkan. Atau bahkan implementasikan sendiri, jika DBMS adalah open source, seperti Postgres.

ypercubeᵀᴹ
sumber
Saya tidak yakin ini akan sesederhana ini .. Bagaimana dengan indeks parsial, atau nilai NULL? dll. NULL mungkin masih berfungsi dengan baik jika Anda senang NULL != NULL. Pokoknya .. :)
Joishi Bodio
@ JoishiBodio Saya tidak berpikir Null adalah masalah. Batasan UNIQUE dapat didefinisikan atau nullable kolom juga. Standarnya adalah jika ada kolom yang memiliki NULL, maka batasan dilewatkan dan baris diterima.
ypercubeᵀᴹ
Namun pada detik, jika a1, a2, ... aN tidak dapat dibatalkan dan b1, b2, bM kita mungkin akan mengalami masalah. Tetapi fitur tersebut tentunya dapat diimplementasikan untuk kolom yang tidak dapat dibatalkan. Apa yang mungkin mengkhawatirkan adalah implikasi efisiensi.
ypercubeᵀᴹ
Saya akrab dengan di UNIQUE INDEXmana kolom NULLABLE.. itulah sebabnya saya menyebutkannya. :) Tapi saya setuju - dalam hal tidak ada NULL (dan bukan indeks parsial juga), mungkin cukup mudah.
Joishi Bodio
5

Kunci Asing secara umum (bukan hanya gabungan) HARUS menunjuk ke KUNCI semacam UNIK semacam di tabel lain. Jika tidak, tidak akan ada integritas data relasional.

Ini mengeluh karena, saat Anda memiliki kunci unik di (id) .. Anda TIDAK memiliki kunci unik di (id, num) .. Dengan demikian, sejauh menyangkut DB, pasangan (id, num) adalah tidak DIJAMIN menjadi unik. Kita, sebagai manusia, dapat mengetahuinya akan menjadi unik, tapi saya yakin akan ada banyak kode tambahan yang harus mereka tambahkan untuk membuat Postgres cukup pintar untuk melihat bahwa "oh hei .. id seharusnya unik , jadi id, num juga harus unik "..

Saya akan sangat terkejut jika mereka menambahkan kode itu ketika yang harus Anda lakukan adalah membuat indeks unik pada dua kolom untuk memperbaiki masalah.

Untuk lebih jelasnya, kode yang mereka harus tambahkan tidak akan hanya kasus sederhana ini ... itu harus menangani semua kasus, bahkan yang mana kunci asing ada di 4+ kolom, dll. Saya yakin Logikanya akan sangat kompleks.

Joishi Bodio
sumber