ฉันสามารถมีคีย์ต่างประเทศที่อ้างอิงคอลัมน์ในมุมมองใน SQL Server ได้หรือไม่


85

ใน SQL Server 2008 และให้

TableA(A_ID, A_Data)
TableB(B_ID, B_Data)
ViewC(A_or_B_ID, A_or_B_Data)

เป็นไปได้หรือไม่ที่จะกำหนดคอลัมน์TableZ(A_or_B_ID, Z_Data)ดังกล่าวให้Z.A_or_B_IDจำกัด ตามค่าที่พบในViewC? สามารถทำได้โดยใช้ Foreign Key เทียบกับมุมมองหรือไม่

คำตอบ:


110

คุณไม่สามารถอ้างอิงมุมมองในคีย์ต่างประเทศ


38
นี่เป็นข้อ จำกัด ของเซิร์ฟเวอร์ SQL หรือเป็นสิ่งที่ไม่สมควรต้องการ?
Aaron Anodide

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

4
นี่เป็นคำตอบที่ดีสำหรับคำถามติดตามเหล่านี้ - stackoverflow.com/questions/3833150/…
Chris Halcrow

ฉันไม่แน่ใจว่าเป็นคำตอบที่ดีสำหรับคำถามเหล่านั้นอย่างไร ... มันเกี่ยวกับ DBMS ที่แตกต่างกันและบอกว่ามุมมองออกแบบมาเพื่อซ่อนรายละเอียดสคีมาและความสะดวกของผู้ใช้ ประการแรกโอเค ... แต่นี่จะไม่ใช่สิ่งแรกที่พบกรณีการใช้งานที่มั่นคงนอกเหนือจากการออกแบบครั้งแรก ประการที่สองฉันไม่แน่ใจว่าทำไม FK ถึงไม่ทำเช่นนั้น มุมมองสามารถเป็นข้อความค้นหาใด ๆ ที่ไม่จำเป็นต้องวาดออกมาจากตารางมันอาจเป็นค่าคงที่จำนวนมากที่รวมเข้าด้วยกัน ... คีย์ต่างประเทศดูเหมือนจะค่อนข้างสมเหตุสมผลในกรณีนั้น หากมีเหตุผลที่ไม่ควรหวังอะไรที่ลึกซึ้งกว่านี้
George Mauer

27

ในคีย์ต่างประเทศรุ่นเก่าของ SQL Server สามารถทำได้ผ่านทริกเกอร์เท่านั้น คุณสามารถเลียนแบบคีย์ต่างประเทศที่กำหนดเองได้โดยสร้างทริกเกอร์แทรกซึ่งตรวจสอบว่าค่าที่แทรกนั้นปรากฏในตารางที่เกี่ยวข้องด้วยหรือไม่


3
ยินดีต้อนรับสู่ StackOverflow ฉันพบคุณค่าในคำตอบของคุณตั้งแต่ให้วิธีแก้ปัญหา แต่คำตอบที่ถูกต้องคือคำตอบที่ยอมรับและคำถามมีอายุมากกว่า 4 ปีดังนั้นฉันจึงไม่ได้ลงคะแนน แต่ไม่ต้องการออกไปโดยไม่มีความคิดเห็นนี้
jachguate

16

หากคุณต้องการA_or_B_IDใน TableZ จริงๆคุณมีสองตัวเลือกที่คล้ายกัน:

1) เพิ่ม nullable A_IDและB_IDคอลัมน์ในตาราง z สร้างA_or_B_IDคอลัมน์ที่คำนวณโดยใช้ ISNULL บนสองคอลัมน์นี้และเพิ่มข้อ จำกัด CHECK เพื่อให้มีเพียงหนึ่งในA_IDหรือB_IDไม่เป็นโมฆะ

2) เพิ่มคอลัมน์ TableName ลงในตาราง z ซึ่งถูก จำกัด ให้มี A หรือ B สร้างA_IDและB_IDเป็นคอลัมน์ที่คำนวณแล้วซึ่งจะไม่เป็นค่าว่างเมื่อมีการตั้งชื่อตารางที่เหมาะสมเท่านั้น (โดยใช้นิพจน์ CASE) ทำให้ติดตาด้วย

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

(ขอบคุณความคิดเห็นสำหรับการแก้ไขการจัดรูปแบบของฉัน)


ใส่คำที่มีเครื่องหมายขีดหลัง: A_or_B_ID
Bill Karwin

ฉันกำลังดำเนินการเพิ่มคุณสมบัติบางอย่างให้กับระบบเดิมและนี่เป็นวิธีที่ดีเยี่ยมในการแก้ไขทั้งเก่าและใหม่เข้าด้วยกัน ขอขอบคุณ!
David Gunderson


4

มีอีกทางเลือกหนึ่ง ถือว่า TableA และ TableB เป็นคลาสย่อยของตารางใหม่ที่เรียกว่า TablePrime ปรับค่า ID ของ TableB เพื่อให้ไม่ตรงกับค่า ID ของ TableA สร้าง ID ใน TablePrime เป็น PK และใส่ ID ทั้งหมดของ TableA และ TableB (ปรับแล้ว) ลงใน TablePrime ทำให้ TableA และ TableB มีความสัมพันธ์ FK บน PK เป็น ID เดียวกันใน TablePrime

ขณะนี้คุณมีรูปแบบ supertype / subtype แล้วและสามารถสร้างข้อ จำกัด ให้กับ TablePrime (เมื่อคุณต้องการ-A-หรือ B ) หรือตารางใดตารางหนึ่ง (เมื่อคุณต้องการเฉพาะ AหรือB เท่านั้น )

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


2

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

ข้อดีก็คือสามารถรับหลายคอลัมน์ทำการคำนวณกับคอลัมน์เหล่านั้นยอมรับค่าว่างและยอมรับค่าที่ไม่ตรงกับคีย์หลักอย่างแม่นยำหรือเปรียบเทียบกับผลลัพธ์ของการรวม

ข้อเสียคือเครื่องมือเพิ่มประสิทธิภาพไม่สามารถใช้เทคนิคสำคัญทั้งหมดของเขาได้


1
ข้อเสียคือเครื่องมือเพิ่มประสิทธิภาพไม่สามารถใช้เทคนิคคีย์ต่างประเทศของเขาได้ทั้งหมด ... ... และฟังก์ชันจะทำงานสำหรับทุกแถวที่คุณแทรก / อัปเดต (ดังนั้นจึงไม่เหมาะสำหรับชุด)
jimbobmcgee

1

ขออภัยในความหมายที่เข้มงวดของคำนี้คุณไม่สามารถตั้งค่าคีย์ต่างประเทศในมุมมองได้ นี่คือเหตุผล:

InnoDB เป็นเครื่องมือจัดเก็บข้อมูลในตัวเครื่องเดียวสำหรับ MySQL ที่มีคีย์ต่างประเทศ ตาราง InnoDB ใด ๆ จะถูกลงทะเบียนใน information_schema.tables ด้วย engine = 'InnoDB'

มุมมองในขณะที่ลงทะเบียนใน information_schema.tables มีเอ็นจินการจัดเก็บ NULL ไม่มีกลไกใดใน MySQL ที่จะมีคีย์ต่างประเทศบนตารางใด ๆ ที่มีกลไกการจัดเก็บข้อมูลที่ไม่ได้กำหนดไว้

ขอบคุณ!


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