Kunci asing mengacu pada kunci utama di beberapa tabel?

92

Saya memiliki dua tabel yaitu employee_ce dan employee_sn di bawah database karyawan.

Keduanya memiliki kolom kunci utama unik masing-masing.

Saya memiliki tabel lain yang disebut deduksi, yang kolom kunci asingnya ingin saya rujuk ke kunci utama employee_ce serta employee_sn. Apakah ini mungkin?

sebagai contoh

employees_ce
--------------
empid   name
khce1   prince

employees_sn
----------------
empid   name
khsn1   princess

jadi apakah ini mungkin?

deductions
--------------
id      name
khce1   gold
khsn1   silver
Cœur
sumber

Jawaban:

99

Dengan asumsi bahwa saya telah memahami skenario Anda dengan benar, inilah yang saya sebut sebagai cara yang benar untuk melakukan ini:

Mulailah dari deskripsi tingkat yang lebih tinggi dari database Anda! Anda memiliki karyawan, dan karyawan dapat menjadi karyawan "ce" dan karyawan "sn" (apa pun itu). Dalam istilah berorientasi objek, ada kelas "karyawan", dengan dua sub-kelas yang disebut "karyawan ce" dan "karyawan sn".

Maka Anda menerjemahkan ini deskripsi tingkat yang lebih tinggi untuk tiga tabel: employees, employees_cedan employees_sn:

  • employees(id, name)
  • employees_ce(id, ce-specific stuff)
  • employees_sn(id, sn-specific stuff)

Karena semua karyawan adalah karyawan (duh!), Setiap karyawan akan mendapat baris dalam employeestabel. Karyawan "ce" juga memiliki baris di employees_cetabel, dan karyawan "sn" juga memiliki baris di employees_sntabel. employees_ce.idadalah kunci asing employees.id, sebagaimana employees_sn.idadanya.

Untuk merujuk ke karyawan dalam bentuk apa pun (ce atau sn), lihat employeestabel. Artinya, kunci asing yang bermasalah harus mengacu pada tabel itu!

Thomas Padron-McCarthy
sumber
17
Bagaimana Anda membuat ce dan sn saling eksklusif? Karena seorang karyawan tidak dapat menjadi ce dan sn pada waktu yang sama, akan menjadi praktik yang baik untuk merefleksikannya dalam database. Saya mengalami masalah ini sekarang.
Rolf
Saya pikir beberapa tombol kolom dapat membantu masalah di komentar saya sebelumnya ... mencari itu sekarang.
Rolf
12
Anda bisa memaksa karyawan untuk berada di satu tabel saja (dan yang benar) dengan menyimpan tipe di tabel dasar serta tabel turunan. Buat id kunci primer, kunci unik pada (id, tipe), kunci asing tabel anak menjadi aktif (id, tipe), dan beri batasan PERIKSA pada setiap tabel anak agar hanya memiliki tipe yang benar. Atau, jika database Anda melakukan kendala pemeriksaan global (dan tanpa penalti kecepatan yang besar), tentu saja Anda dapat melakukan pemeriksaan TIDAK ADA.
derobert
Periksa Jawaban ini untuk penjelasan lengkap dan detail implementasi.
PerformanceDBA
bagaimana cara mengetahui karyawan dengan id tertentu adalah 'se' atau 'sn'?
mhrsalehi
22

Anda mungkin dapat menambahkan dua batasan kunci asing (sejujurnya: saya belum pernah mencobanya), tetapi kemudian bersikeras baris induk ada di kedua tabel.

Sebagai gantinya Anda mungkin ingin membuat supertipe untuk dua subtipe karyawan Anda, lalu arahkan kunci asing ke sana. (Dengan asumsi Anda memiliki alasan bagus untuk membagi dua jenis karyawan, tentunya).

                 employee       
employees_ce     ————————       employees_sn
————————————     type           ————————————
empid —————————> empid <——————— empid
name               /|\          name
                    |  
                    |  
      deductions    |  
      ——————————    |  
      empid ————————+  
      name

typedi tabel karyawan akan menjadi ceatau sn.

derobert
sumber
Saya mencoba menambahkan beberapa kunci asing, mereka berfungsi tetapi, saat menambahkan catatan, java derby memberi tahu saya bahwa kedua batasan kunci asing telah dilanggar!
Saya baru saja mencobanya di PostgreSQL, dan berfungsi di sana. Apakah Anda memiliki catatan induk di kedua tabel?
derobert
catatan orang tua yang ingin Anda katakan, empid?
Tentunya masalah telah bergeser dari tabel "pemotongan" ke tabel "karyawan". Bagaimana Anda mereferensikan Entitas yang berpotensi berbeda berdasarkan suatu jenis?
gawpertron
1
@gawpertron: Ya, empid unik di semua jenis. Anda dapat menggunakan kolom 'type' untuk melihat sub-tabel mana yang perlu Anda rujuk. Atau LEFT JOINsemuanya, jika jumlahnya cukup. Saat tidak menggunakan tabel dasar 'karyawan', kunci utama tidak dapat dideklarasikan (karena ini merujuk pada tableA atau tableB atau…); sekarang bisa. Kebijaksanaan membelah employees_cedan employees_sndiasumsikan, dan asumsi itu dicatat.
derobert
20

Sebenarnya saya melakukan ini sendiri. Saya memiliki tabel bernama 'Komentar' yang berisi komentar untuk rekaman di 3 tabel lainnya. Tidak ada solusi yang benar-benar menangani semua yang mungkin Anda inginkan. Dalam kasus Anda, Anda akan melakukan ini:

Solusi 1:

  1. Tambahkan bidang tinyint ke employee_ce dan employee_sn yang memiliki nilai default yang berbeda di setiap tabel (Bidang ini mewakili 'pengenal tabel', jadi kami akan menyebutnya tid_ce & tid_sn)

  2. Buat Indeks Unik di setiap tabel menggunakan PK tabel dan bidang id tabel.

  3. Tambahkan bidang tinyint ke tabel 'Pemotongan' Anda untuk menyimpan paruh kedua kunci asing (ID Tabel)

  4. Buat 2 kunci asing di tabel 'Pemotongan' Anda (Anda tidak dapat menerapkan integritas referensial, karena salah satu kunci akan valid atau yang lainnya ... tetapi tidak pernah keduanya:

    ALTER TABLE [dbo].[Deductions]  WITH NOCHECK ADD  CONSTRAINT [FK_Deductions_employees_ce] FOREIGN KEY([id], [fk_tid])
    REFERENCES [dbo].[employees_ce] ([empid], [tid])
    NOT FOR REPLICATION 
    GO
    ALTER TABLE [dbo].[Deductions] NOCHECK CONSTRAINT [FK_600_WorkComments_employees_ce]
    GO
    ALTER TABLE [dbo].[Deductions]  WITH NOCHECK ADD  CONSTRAINT [FK_Deductions_employees_sn] FOREIGN KEY([id], [fk_tid])
    REFERENCES [dbo].[employees_sn] ([empid], [tid])
    NOT FOR REPLICATION 
    GO
    ALTER TABLE [dbo].[Deductions] NOCHECK CONSTRAINT [FK_600_WorkComments_employees_sn]
    GO
    
    employees_ce
    --------------
    empid    name     tid
    khce1   prince    1
    
    employees_sn
    ----------------
    empid    name     tid 
    khsn1   princess  2
    
    deductions
    ----------------------
    id      tid       name  
    khce1   1         gold
    khsn1   2         silver         
    ** id + tid creates a unique index **
    

Solusi 2: Solusi ini memungkinkan integritas referensial dipertahankan: 1. Buat bidang kunci asing kedua di tabel 'Potongan', izinkan nilai Null di kedua kunci asing, dan buat kunci asing normal:

    employees_ce
    --------------
    empid   name
    khce1   prince 

    employees_sn
    ----------------
    empid   name     
    khsn1   princess 

    deductions
    ----------------------
    idce    idsn      name  
    khce1   *NULL*    gold
    *NULL*  khsn1     silver         

Integritas hanya dicentang jika kolomnya bukan nol, sehingga Anda dapat mempertahankan integritas referensial.

LittleC
sumber
6

Saya tahu ini adalah topik stagnan yang lama, tetapi jika ada yang mencari di sini adalah bagaimana saya menangani kunci asing multi tabel. Dengan teknik ini, Anda tidak memiliki operasi kaskade yang diberlakukan DBA, jadi pastikan Anda menangani DELETEdan semacamnya di kode Anda.

Table 1 Fruit
pk_fruitid, name
1, apple
2, pear

Table 2 Meat
Pk_meatid, name
1, beef
2, chicken

Table 3 Entity's
PK_entityid, anme
1, fruit
2, meat
3, desert

Table 4 Basket (Table using fk_s)
PK_basketid, fk_entityid, pseudo_entityrow
1, 2, 2 (Chicken - entity denotes meat table, pseudokey denotes row in indictaed table)
2, 1, 1 (Apple)
3, 1, 2 (pear)
4, 3, 1 (cheesecake)

Contoh SO Op akan terlihat seperti ini

deductions
--------------
type    id      name
1      khce1   gold
2      khsn1   silver

types
---------------------
1 employees_ce
2 employees_sn
Brian Sallee
sumber
1

Secara teknis mungkin. Anda mungkin akan mereferensikan employee_ce dalam potongan dan employee_sn. Tetapi mengapa Anda tidak menggabungkan employee_sn dan employee_ce? Saya tidak melihat alasan mengapa Anda memiliki dua meja. Tidak ada satu dengan banyak hubungan. Dan (tidak dalam contoh ini) banyak kolom.

Jika Anda melakukan dua referensi untuk satu kolom, seorang karyawan harus memiliki entri di kedua tabel.

Sascha
sumber
1

Ya, itu mungkin. Anda perlu menentukan 2 FK untuk tabel ke-3. Setiap FK menunjuk ke field wajib dari satu tabel (yaitu 1 FK per tabel asing).

vmarquez.dll
sumber
0

Dengan asumsi Anda harus memiliki dua tabel untuk dua jenis karyawan karena alasan tertentu, saya akan memperluas jawaban vmarquez:

Skema:

employees_ce (id, name)
employees_sn (id, name)
deductions (id, parentId, parentType, name)

Data dalam potongan:

deductions table
id      parentId      parentType      name
1       1             ce              gold
2       1             sn              silver
3       2             sn              wood
...

Ini akan memungkinkan Anda untuk memiliki poin deduksi ke tabel lain dalam skema Anda. Jenis hubungan ini tidak didukung oleh batasan tingkat database, IIRC jadi Anda harus memastikan Aplikasi Anda mengelola batasan dengan benar (yang membuatnya lebih rumit jika Anda memiliki beberapa Aplikasi / layanan berbeda yang menggunakan database yang sama).

r00fus.dll
sumber