Tambahkan hubungan Kunci Asing antara dua Database

91

Saya memiliki dua tabel dalam dua database yang berbeda. Dalam tabel1 (dalam database1) ada kolom yang disebut kolom1 dan itu adalah kunci utama. Sekarang di tabel2 (di database2) ada kolom bernama kolom2 dan saya ingin menambahkannya sebagai kunci asing.

Saya mencoba menambahkannya dan itu memberi saya kesalahan berikut:

Psn 1763, Level 16, Status 0, Baris 1
Referensi kunci asing lintas database tidak didukung. Database2.table2 kunci asing.

Msg 1750, Level 16, Status 0, Baris 1
Tidak dapat membuat batasan. Lihat kesalahan sebelumnya.

Bagaimana saya melakukannya karena tabel berada dalam database yang berbeda.

Sam
sumber

Jawaban:

84

Anda perlu mengelola batasan referensial di seluruh database menggunakan Trigger.


Pada dasarnya Anda membuat pemicu penyisipan, pembaruan untuk memverifikasi keberadaan Kunci dalam tabel Kunci utama. Jika kunci tidak ada maka kembalikan penyisipan atau pembaruan dan kemudian tangani pengecualian.

Contoh:

Create Trigger dbo.MyTableTrigger ON dbo.MyTable, After Insert, Update
As
Begin

   If NOT Exists(select PK from OtherDB.dbo.TableName where PK in (Select FK from inserted) BEGIN
      -- Handle the Referential Error Here
   END

END

Diedit: Hanya untuk memperjelas. Ini bukan pendekatan terbaik dengan menegakkan integritas referensial. Idealnya Anda menginginkan kedua tabel dalam db yang sama tetapi jika itu tidak memungkinkan. Maka hal di atas adalah solusi potensial untuk Anda.

John Hartsock
sumber
4
@ John Hartsock - contoh di atas dapat dengan mudah gagal, tanpa menambahkan penanganan transaksi yang sesuai. Diskusi yang layak tentang jenis masalah yang dapat terjadi dengan "jika tidak ada () maka masukkan" dapat ditemukan di sini - stackoverflow.com/questions/108403/…
EBarr
17
@ John Hartsock - solusi Anda memiliki celah: jika salah satu dari dua database dipulihkan dari cadangan, tentu saja pemicu tidak akan diaktifkan. Ini adalah bagaimana kita bisa berakhir dengan baris yatim piatu.
AK
4
@AlexKuzv Tepat. Seperti yang saya jelaskan, ini bukan pendekatan terbaik tetapi potensi penyelesaian.
John Hartsock
2
Ini sangat salah ... Saya hanya berharap OP menyadari bahwa hanya fakta bahwa dia menanyakan sesuatu seperti ini, adalah gejala bahwa dia kemungkinan besar melakukan sesuatu yang salah ... apalagi memikirkan pemicu ..
MeTitus
1
@Marco Seperti yang saya posting di jawaban saya "Hanya untuk memperjelas. Ini bukan pendekatan terbaik dengan menegakkan integritas referensial. Idealnya Anda ingin kedua tabel dalam db yang sama tetapi jika itu tidak memungkinkan. Maka di atas adalah solusi potensial untuk kamu." Saya menjelaskan bahwa ini mungkin bukan ide yang bagus.
John Hartsock
48

Jika Anda membutuhkan integritas yang kokoh, miliki kedua tabel dalam satu database, dan gunakan batasan FK. Jika tabel induk Anda ada di database lain, tidak ada yang mencegah siapa pun memulihkan database induk tersebut dari cadangan lama, dan kemudian Anda memiliki yatim piatu.

Inilah mengapa FK antar database tidak didukung.

AK
sumber
27

Menurut pengalaman saya, cara terbaik untuk menangani ini ketika sumber informasi otoritatif utama untuk dua tabel yang terkait harus berada dalam dua database terpisah adalah dengan menyinkronkan salinan tabel dari lokasi utama ke lokasi sekunder (menggunakan T- SQL atau SSIS dengan pemeriksaan kesalahan yang sesuai - Anda tidak dapat memotong dan mengisi kembali tabel saat tabel memiliki referensi kunci asing, jadi ada beberapa cara untuk mengupdate kucing pada tabel).

Kemudian tambahkan hubungan FK tradisional di lokasi kedua ke tabel yang secara efektif merupakan salinan hanya-baca.

Anda dapat menggunakan pemicu atau pekerjaan terjadwal di lokasi utama untuk terus memperbarui salinan.

Cade Roux
sumber
1
Kembali. "Anda dapat memicu atau menjadwalkan pekerjaan di lokasi utama agar salinan tetap diperbarui": Mengapa tidak hanya menggunakan Replikasi SQL Server (khususnya jenis Transaksi vs. Gabung sejak salinan Pelanggan (salinan yang memiliki Tabel yang memerlukan Batasan Kunci Asing) saja harus hanya-baca)? Lihat: tautan
Tom
@Tom ya, Anda pasti dapat menggunakan replikasi untuk menyimpan salinan tabel diperbarui dalam database jarak jauh.
Cade Roux
21

Anda dapat menggunakan kendala pemeriksaan dengan fungsi yang ditentukan pengguna untuk melakukan pemeriksaan. Ini lebih dapat diandalkan daripada pemicu. Ini dapat dinonaktifkan dan diaktifkan kembali bila diperlukan sama seperti kunci asing dan diperiksa ulang setelah pemulihan database2.

CREATE FUNCTION dbo.fn_db2_schema2_tb_A
(@column1 INT) 
RETURNS BIT
AS
BEGIN
    DECLARE @exists bit = 0
    IF EXISTS (
      SELECT TOP 1 1 FROM DB2.SCHEMA2.tb_A 
      WHERE COLUMN_KEY_1 =  @COLUMN1
    ) BEGIN 
         SET @exists = 1 
      END;
      RETURN @exists
END
GO

ALTER TABLE db1.schema1.tb_S
  ADD CONSTRAINT CHK_S_key_col1_in_db2_schema2_tb_A
    CHECK(dbo.fn_db2_schema2_tb_A(key_col1) = 1)
Camilo J
sumber
1
ini adalah solusi yang lebih baik daripada jawaban yang diterima dan Anda juga dapat menggunakannya kembali di beberapa tabel
Milox
3

Jawaban singkatnya adalah bahwa SQL Server (pada SQL 2008) tidak mendukung kunci asing database silang - seperti yang dinyatakan dalam pesan kesalahan.

Meskipun Anda tidak dapat memiliki integritas referensial deklaratif (FK), Anda dapat mencapai tujuan yang sama menggunakan pemicu. Ini agak kurang dapat diandalkan, karena logika yang Anda tulis mungkin memiliki bug, tetapi itu akan membawa Anda ke sana sama saja.

Lihat dokumen SQL @ http://msdn.microsoft.com/en-us/library/aa258254%28v=sql.80%29.aspx Status mana:

Pemicu sering kali digunakan untuk menegakkan aturan bisnis dan integritas data. SQL Server menyediakan integritas referensial deklaratif (DRI) melalui pernyataan pembuatan tabel (ALTER TABLE dan CREATE TABLE); namun, DRI tidak menyediakan integritas referensial lintas database. Untuk menegakkan integritas referensial (aturan tentang hubungan antara kunci primer dan asing tabel), gunakan batasan kunci utama dan asing (kata kunci PRIMARY KEY dan FOREIGN KEY dari ALTER TABLE dan CREATE TABLE). Jika ada batasan pada tabel pemicu, mereka diperiksa setelah BUKAN eksekusi pemicu dan sebelum eksekusi pemicu SETELAH. Jika batasan dilanggar, BUKAN tindakan pemicu digulung kembali dan pemicu SETELAH tidak dijalankan (diaktifkan).

Ada juga diskusi OK di SQLTeam - http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=31135

EBarr
sumber
0

Seperti pesan kesalahan mengatakan, ini tidak didukung di sql server. Satu-satunya cara untuk memastikan integritas referential adalah bekerja dengan pemicu.

Jan
sumber
1
Bisakah Anda menjelaskan saya dengan sebuah contoh
Sam