เพิ่มความสัมพันธ์ของ Foreign Key ระหว่างสองฐานข้อมูล


92

ฉันมีสองตารางในสองฐานข้อมูลที่แตกต่างกัน ใน table1 (ในฐานข้อมูล 1) มีคอลัมน์ชื่อ column1 และเป็นคีย์หลัก ตอนนี้ใน table2 (ใน database2) มีคอลัมน์ชื่อ column2 และฉันต้องการเพิ่มเป็นคีย์ต่างประเทศ

ฉันพยายามเพิ่มมันและทำให้ฉันมีข้อผิดพลาดต่อไปนี้:

ข่าวสารเกี่ยวกับ 1763 ระดับ 16 สถานะ 0 บรรทัด 1
การอ้างอิงคีย์ต่างประเทศข้ามฐานข้อมูลไม่ได้รับการสนับสนุน ฐานข้อมูลคีย์ต่างประเทศ 2.table2.

ข่าวสารเกี่ยวกับ 1750 ระดับ 16 สถานะ 0 บรรทัด 1
ไม่สามารถสร้างข้อ จำกัด ดูข้อผิดพลาดก่อนหน้านี้

ฉันจะทำเช่นนั้นได้อย่างไรเนื่องจากตารางอยู่ในฐานข้อมูลที่แตกต่างกัน

คำตอบ:


84

คุณจะต้องจัดการข้อ จำกัด ในการอ้างอิงในฐานข้อมูลโดยใช้ Trigger


โดยทั่วไปคุณจะสร้างส่วนแทรกอัพเดตทริกเกอร์เพื่อตรวจสอบการมีอยู่ของคีย์ในตารางคีย์หลัก หากไม่มีคีย์ให้ย้อนกลับการแทรกหรืออัพเดตจากนั้นจัดการข้อยกเว้น

ตัวอย่าง:

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

แก้ไข: เพื่อชี้แจง นี่ไม่ใช่แนวทางที่ดีที่สุดในการบังคับใช้ความสมบูรณ์ของการอ้างอิง ตามหลักการแล้วคุณต้องการให้ทั้งสองตารางอยู่ในฐานข้อมูลเดียวกัน แต่ถ้าเป็นไปไม่ได้ จากนั้นข้างต้นเป็นวิธีแก้ปัญหาที่อาจเกิดขึ้นสำหรับคุณ


4
@ John Hartsock - ตัวอย่างข้างต้นสามารถล้มเหลวได้อย่างง่ายดายโดยไม่ต้องเพิ่มการจัดการธุรกรรมที่เหมาะสม การอภิปรายที่เหมาะสมเกี่ยวกับประเภทของปัญหาที่อาจเกิดขึ้นกับ "ถ้าไม่มี () ให้แทรก" มีอยู่ที่นี่ - stackoverflow.com/questions/108403/…
EBarr

17
@ John Hartsock - โซลูชันของคุณมีช่องโหว่: หากฐานข้อมูลหนึ่งในสองฐานข้อมูลถูกกู้คืนจากข้อมูลสำรองทริกเกอร์จะไม่เริ่มทำงานแน่นอน นี่คือวิธีที่เราสามารถลงท้ายด้วยแถว orphan
AK

4
@AlexKuznetsov แน่นอน ดังที่ฉันได้อธิบายว่านี่ไม่ใช่แนวทางที่ดีที่สุด แต่เป็นวิธีการแก้ไขที่มีศักยภาพ
John Hartsock

2
นี่มันผิดมาก ... ฉันแค่หวังว่า OP จะรู้ว่าการที่เขาถามเรื่องแบบนี้มันเป็นอาการที่บ่งบอกว่าเขามักจะทำอะไรผิดพลาด ... นับประสาอะไรกับการกระตุ้น ..
MeTitus

1
@Marco ตามที่ฉันโพสต์ไว้ในคำตอบของฉัน "เพียงเพื่อชี้แจงนี่ไม่ใช่แนวทางที่ดีที่สุดในการบังคับใช้ความสมบูรณ์ของการอ้างอิงตามหลักการแล้วคุณต้องการให้ทั้งสองตารางอยู่ในฐานข้อมูลเดียวกัน แต่ถ้าเป็นไปไม่ได้ข้างต้นก็เป็นแนวทางที่อาจเกิดขึ้นได้สำหรับ คุณ." ฉันอธิบายว่านี่อาจไม่ใช่ความคิดที่ดี
John Hartsock

48

หากคุณต้องการความสมบูรณ์ที่มั่นคงให้มีทั้งสองตารางในฐานข้อมูลเดียวและใช้ข้อ จำกัด FK ถ้าตารางพาเรนต์ของคุณอยู่ในฐานข้อมูลอื่นไม่มีอะไรป้องกันไม่ให้ใครกู้คืนฐานข้อมูลพาเรนต์นั้นจากข้อมูลสำรองเก่าแล้วคุณมีเด็กกำพร้า

นี่คือสาเหตุที่ไม่รองรับ FK ระหว่างฐานข้อมูล


27

จากประสบการณ์ของฉันวิธีที่ดีที่สุดในการจัดการสิ่งนี้เมื่อแหล่งข้อมูลที่เชื่อถือได้หลักสำหรับสองตารางที่เกี่ยวข้องกันต้องอยู่ในฐานข้อมูลสองฐานข้อมูลที่แยกจากกันคือการซิงค์สำเนาของตารางจากตำแหน่งหลักไปยังตำแหน่งรอง (โดยใช้ T- SQL หรือ SSIS ด้วยการตรวจสอบข้อผิดพลาดที่เหมาะสม - คุณไม่สามารถตัดทอนและสร้างตารางใหม่ได้ในขณะที่มีการอ้างอิงคีย์ต่างประเทศดังนั้นจึงมีสองสามวิธีในการสกิน cat บนตารางที่อัปเดต)

จากนั้นเพิ่มความสัมพันธ์ FK ดั้งเดิมในตำแหน่งที่สองลงในตารางซึ่งเป็นสำเนาแบบอ่านอย่างเดียวอย่างมีประสิทธิภาพ

คุณสามารถใช้ทริกเกอร์หรืองานที่กำหนดเวลาไว้ในตำแหน่งหลักเพื่ออัปเดตสำเนา


1
เรื่อง "คุณสามารถทริกเกอร์หรือกำหนดเวลางานในตำแหน่งหลักเพื่อให้สำเนาอัปเดต": ทำไมไม่ใช้เพียงแค่การจำลองแบบเซิร์ฟเวอร์ SQL (โดยเฉพาะประเภทธุรกรรมเทียบกับการผสานเนื่องจากสำเนาของสมาชิก (สำเนาที่มีตารางที่ต้องการข้อ จำกัด ของคีย์ต่างประเทศ) เพียง ต้องอ่านอย่างเดียว)? ดู: ลิงค์
ทอม

@ ทอมใช่คุณสามารถใช้การจำลองแบบเพื่อให้สำเนาของตารางอัปเดตในฐานข้อมูลระยะไกลได้อย่างแน่นอน
Cade Roux

21

คุณสามารถใช้ข้อ จำกัด การตรวจสอบกับฟังก์ชันที่ผู้ใช้กำหนดเพื่อทำการตรวจสอบ มีความน่าเชื่อถือมากกว่าทริกเกอร์ สามารถปิดใช้งานและเปิดใช้งานใหม่ได้เมื่อจำเป็นเช่นเดียวกับคีย์ต่างประเทศและตรวจสอบอีกครั้งหลังจากกู้คืนฐานข้อมูล 2

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)

1
นี่เป็นทางออกที่ดีกว่าคำตอบที่ยอมรับและคุณสามารถใช้ซ้ำได้ในหลาย ๆ โต๊ะ
Milox

3

คำตอบสั้น ๆ คือ SQL Server (ณ SQL 2008) ไม่รองรับคีย์ต่างประเทศข้ามฐานข้อมูล - เนื่องจากข้อความแสดงข้อผิดพลาดระบุ

แม้ว่าคุณจะไม่มีความสมบูรณ์ของการอ้างอิงที่เปิดเผย (FK) แต่คุณสามารถบรรลุเป้าหมายเดียวกันได้โดยใช้ทริกเกอร์ มีความน่าเชื่อถือน้อยกว่าเล็กน้อยเนื่องจากตรรกะที่คุณเขียนอาจมีข้อบกพร่อง แต่จะทำให้คุณเหมือนเดิม

ดูเอกสาร SQL @ http://msdn.microsoft.com/en-us/library/aa258254%28v=sql.80%29.aspxสถานะใด:

ทริกเกอร์มักใช้เพื่อบังคับใช้กฎทางธุรกิจและความสมบูรณ์ของข้อมูล SQL Server จัดเตรียมความสมบูรณ์ของการอ้างอิง (DRI) ผ่านคำสั่งการสร้างตาราง (แก้ไขตารางและสร้างตาราง) อย่างไรก็ตาม DRI ไม่ได้ให้ความสมบูรณ์ของการอ้างอิงข้ามฐานข้อมูล ในการบังคับใช้ referential Integrity (กฎเกี่ยวกับความสัมพันธ์ระหว่างคีย์หลักและคีย์ต่างประเทศของตาราง) ให้ใช้ข้อ จำกัด ของคีย์หลักและคีย์ต่างประเทศ (คีย์หลักและคีย์เวิร์ดต่างประเทศของ ALTER TABLE และ CREATE TABLE) หากมีข้อ จำกัด บนตารางทริกเกอร์จะมีการตรวจสอบหลังจากการเรียกใช้ทริกเกอร์ INSTEAD OF และก่อนที่จะดำเนินการหลังทริกเกอร์ หากละเมิดข้อ จำกัด การกระทำของทริกเกอร์แทนจะถูกย้อนกลับและทริกเกอร์ AFTER จะไม่ถูกดำเนินการ (ยิง)

นอกจากนี้ยังมีการอภิปรายตกลงที่ SQLTeam - http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=31135


0

ตามข้อความแสดงข้อผิดพลาดนี้ไม่ได้รับการสนับสนุนบนเซิร์ฟเวอร์ sql วิธีเดียวที่จะรับประกันความสมบูรณ์ของการอ้างอิงคือการทำงานกับทริกเกอร์


1
คุณช่วยอธิบายฉันด้วยตัวอย่างได้ไหม
แซม
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.