Foreign Key ที่เป็นโมฆะปฏิบัติไม่ดี?


114

สมมติว่าคุณมีตารางคำสั่งซื้อที่มีคีย์ต่างประเทศเป็นรหัสลูกค้า ตอนนี้สมมติว่าคุณต้องการเพิ่มคำสั่งซื้อโดยไม่มีรหัสลูกค้า (คำถามอื่นควรเป็นไปได้หรือไม่) คุณจะต้องทำให้คีย์ต่างประเทศเป็น NULL ... เป็นการปฏิบัติที่ไม่ดีหรือคุณควรใช้ตารางลิงก์ระหว่าง คำสั่งซื้อและลูกค้า? แม้ว่าความสัมพันธ์คือ 1 ถึง n ตารางลิงก์จะทำให้ n ถึง n ในทางกลับกันด้วยตารางลิงค์ฉันไม่มี NULLS อีกต่อไป ...

จะไม่มี NULL อยู่ในฐานข้อมูลมากนักเนื่องจากระเบียนที่มี Foreign Key เป็น NULL จะเป็นเพียงชั่วคราวจนกว่าจะมีการเพิ่มลูกค้าสำหรับคำสั่งซื้อ

(ในกรณีของฉันไม่ใช่คำสั่งซื้อและลูกค้า)

แก้ไข: ลูกค้าที่ยังไม่ได้มอบหมายจะเชื่อมโยงไปถึงอะไร?


9
นั่นเป็นหนึ่งในจุดประสงค์หลักของการมี NULL ในสคีมาฐานข้อมูล นอกจากนี้นั่นคือเหตุผลที่คุณสามารถประกาศฟิลด์ NULL หรือ NOT NULL เพื่อให้ตรงตามข้อกำหนดเฉพาะของสคีมาของคุณ
gahooa

7
ตอนแรกฉันอ่านคำถามในฐานะคีย์หลักที่เป็นโมฆะและกำลังจะดำเนินการตามคำแนะนำที่ชัดเจน ... :-)
Andrzej Doyle

คำตอบ:


51

การมีตารางลิงค์น่าจะเป็นตัวเลือกที่ดีกว่า อย่างน้อยก็ไม่ละเมิดการปรับมาตรฐานBCNF (รูปแบบปกติ Boyce-Codd) อย่างไรก็ตามฉันชอบเป็นคนชอบปฏิบัติ หากคุณมีค่าว่างเหล่านี้น้อยมากและเป็นเพียงชั่วคราวฉันคิดว่าคุณควรข้ามตารางลิงก์เนื่องจากจะเพิ่มความซับซ้อนให้กับโครงร่างเท่านั้น

หมายเหตุด้านข้าง; การใช้ตารางลิงก์ไม่จำเป็นต้องทำให้เป็น n ถึง n หากคุณในตารางลิงก์ใช้คีย์ต่างประเทศที่ชี้ไปยังตารางคำสั่งซื้อของคุณเป็นคีย์หลักในตารางลิงก์นั้นความสัมพันธ์จะยังคงเป็น 1..n สามารถมีได้เพียงรายการเดียวในตารางลิงก์ต่อคำสั่งซื้อ


2
source__destination_link หรือ SourceDestination
Svisstack

7
ฉันสนใจที่จะได้ยินเกี่ยวกับสถานการณ์เมื่อมีตารางลิงก์จะดีกว่าฉันไม่เคยเจอสถานการณ์ที่จะช่วยปรับปรุงกระบวนการไหล แต่อย่างใด
Reimius

5
ดังที่ได้ระบุไว้ในคำตอบของฉันฉันจะปฏิบัติในกรณีนี้โดยเฉพาะและไม่ใช้ตารางลิงค์ ฉันแน่ใจว่ารูปแบบปกติไม่ได้ถูกคิดค้นขึ้นเพื่อปรับปรุงโฟลว์ของกระบวนการ แต่เพื่อให้แน่ใจว่ามีความสม่ำเสมอและเพื่อหลีกเลี่ยงความซ้ำซ้อน แม้ว่าจะเป็นการอภิปรายทั่วไป แต่ฉันคิดว่าต้องดูเป็นกรณี ๆ ไป
Patrik Hägne

110

ไม่ไม่มีอะไรผิดปกติกับ Nullable FKs นี่เป็นเรื่องปกติเมื่อเอนทิตีที่ FK ชี้ไปอยู่ในความสัมพันธ์ (ศูนย์หรือหนึ่ง) ถึง (1 หรือหลายตัว) กับตารางที่อ้างอิงคีย์หลัก

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


39

คอลัมน์ Nullable สามารถอยู่ใน 1NF ถึง 5NF แต่ไม่ใช่ใน 6NF ตามสิ่งที่ฉันอ่าน

เฉพาะในกรณีที่คุณรู้ดีกว่า Chris Date "รูปแบบปกติแรกหมายถึงอะไร" ถ้า x และ y มีทั้ง nullable และแน่นอนในบางแถว x และ y มีทั้งที่nullแล้วไม่ได้ผลตอบแทนWHERE x=y trueสิ่งนี้พิสูจน์ได้โดยปราศจากข้อสงสัยที่สมเหตุสมผลว่า null ไม่ใช่ค่า (เนื่องจากมูลค่าจริงใด ๆ จะเท่ากับตัวมันเองเสมอ) และเนื่องจาก RM กำหนดว่า "ต้องมีค่าในทุกเซลล์ของตาราง" สิ่งใด ๆ ที่อาจมีค่าว่างไม่ใช่สิ่งที่สัมพันธ์กันดังนั้นคำถามของ 1NF จึงไม่เกิดขึ้นด้วยซ้ำ

ฉันได้ยินมาว่ามันเป็นที่ถกเถียงกันอยู่ว่าคอลัมน์ Nullable โดยทั่วไปจะทำลายระดับแรกของการทำให้เป็นมาตรฐาน

ดูด้านบนสำหรับเหตุผลที่ดีที่เป็นรากฐานของข้อโต้แย้งนั้น

แต่ในทางปฏิบัติมันใช้ได้จริง

เฉพาะในกรณีที่คุณมีภูมิคุ้มกันต่ออาการปวดหัวซึ่งมักจะเป็นสาเหตุของคนทั่วโลก อาการปวดหัวอย่างหนึ่ง (และเป็นเพียงเล็กน้อยเมื่อเทียบกับnullปรากฏการณ์อื่น ๆ) คือความจริงที่ว่าWHERE x=yใน SQL หมายถึงจริงWHERE x is not null and y is not null and x=yแต่โปรแกรมเมอร์ส่วนใหญ่ไม่ได้ตระหนักถึงข้อเท็จจริงนั้นและเพียงแค่อ่านมัน บางครั้งไม่มีอันตรายใด ๆ ในบางครั้งไม่

ในความเป็นจริงคอลัมน์ที่เป็นโมฆะได้ละเมิดกฎพื้นฐานที่สุดข้อหนึ่งในการออกแบบฐานข้อมูล: อย่ารวมองค์ประกอบข้อมูลที่แตกต่างกันในคอลัมน์เดียว Nulls ทำเช่นนั้นเพราะรวมค่าบูลีน "ฟิลด์นี้เป็น / ไม่มีอยู่จริง" เข้ากับค่าจริง


18
+1 สำหรับ "WHERE x ไม่เป็นโมฆะและ y ไม่ใช่ค่าว่างและ x = y" ไม่ทราบว่า
RobM

1
การโต้แย้งและตัวอย่างที่วางไว้อย่างดีมาก
pedz

1
ปัญหาหนึ่ง. เมื่อค่า "ไม่มีอยู่" (ซึ่งเป็นสถานการณ์ในโลกแห่งความจริง) และแอตทริบิวต์ฐานข้อมูลไม่อนุญาตให้มีค่าว่างค่าใดก็ตามที่อยู่ในแอตทริบิวต์จะผิด สำหรับอาการปวดหัวโปรดจำไว้ว่า KISS ไม่ได้หมายความเพียงแค่ทำให้มันเรียบง่าย แต่หมายถึง Keep it as simple as possible, but no simpler. หาก "โมเดลเชิงสัมพันธ์" ต้องการผลลัพธ์ที่ไม่สมจริงและโง่เขลาบางทีกฎอาจต้องขยายเพื่อจัดการกับข้อมูลในโลกแห่งความจริงที่จำเป็น?
Charles Bretana

1
มีการแสดงให้เห็นว่าตรรกะที่มีค่าสามค่านำไปสู่ความต้องการตรรกะสี่ค่าและนั่นนำไปสู่ความต้องการตรรกะที่มีค่า 5 ค่า ฯลฯ ตรรกะที่มีค่า 2 ค่าก็เพียงพอแล้ว แต่โครงสร้างข้อมูลที่เราได้รับเมื่อ การใช้มันทำให้ "ง่ายที่สุดเท่าที่จะเป็นไปได้" แต่ยังง่ายน้อยกว่า "ง่ายที่สุดเท่าที่เราต้องการ"
Erwin Smout

2
Chris Date, Logic & Databases, Chpt 6, "ทำไมตรรกะ DBMS เชิงสัมพันธ์ต้องไม่มีมูลค่ามากมาย", หน้า 145 รายการการอ้างอิงถึงบทนั้นควรมีความน่าสนใจโดยเฉพาะอย่างยิ่งที่เกี่ยวข้องกับ McGoveran
Erwin Smout

13

ฉันไม่เห็นอะไรผิดปกติเนื่องจากมันเป็นเพียงความสัมพันธ์ n-1 ที่เป็นทางเลือกซึ่งจะแสดงด้วย null ในคีย์นอกประเทศ มิฉะนั้นหากคุณใส่ตารางลิงค์คุณจะต้องจัดการไม่ให้มันกลายเป็นความสัมพันธ์แบบ nn ซึ่งจะทำให้เกิดปัญหามากยิ่งขึ้น


2
จริงๆแล้วมันเป็นความสัมพันธ์ 0-N ไม่ใช่ความสัมพันธ์แบบ 1-N ที่เป็นทางเลือก แต่ฉันเห็นด้วยกับคุณ
Eric J.

5
จัดการ? มันเป็นข้อ จำกัด ที่ไม่ซ้ำใครง่ายๆในด้าน 0 ต่อ 1!
wqw

2
ใช่มันเป็นข้อ จำกัด ที่ไม่ซ้ำใคร แต่คุณจะต้องจัดการกับข้อยกเว้นที่เป็นไปได้ในภายหลังด้วยในรหัสของคุณเนื่องจากข้อ จำกัด นั้น ...
pedromarce

4

ความสัมพันธ์ทางเลือกเป็นไปได้อย่างแน่นอนในโมเดลเชิงสัมพันธ์

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

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


2

การใช้ NULL จะเป็นวิธีที่ดีในการล้างคำสั่งซื้อที่ไม่สมบูรณ์:

SELECT * FROM `orders`
WHERE `started_time` < (UNIX_TIMESTAMP() + 900) AND `customer_id` IS NULL

ข้างต้นจะแสดงคำสั่งซื้อที่เก่ากว่า 15 นาทีโดยไม่มีรหัสลูกค้าที่เกี่ยวข้อง


1

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

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

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


ลูกค้าที่สั่งซื้อเป็นตัวอย่าง ในแอปของฉันมันเหมือนกับที่อยู่มากกว่า ไม่พบตัวอย่างที่ถูกต้องในทันที ขอบคุณ.
Lieven Cardoen

1
นี่อาจเป็นสถานการณ์ที่ถูกต้องหากมีการใช้ฐานข้อมูลเพื่อจัดเก็บสินค้าในตะกร้าสินค้าโดยที่ตะกร้าสินค้าไม่ได้เป็นของผู้ใช้ที่ลงทะเบียน
Johnie Karr

1

คุณสามารถเพิ่มแถวเทียมลงในตารางลูกค้าของคุณได้ตลอดเวลาเช่น Id = -1 และ CustomerName = 'Unknown' จากนั้นในกรณีที่คุณตั้ง CustomerId ตามปกติใน Order NULL ให้ตั้งค่าเป็น -1

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


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

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

0

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


-1

ฉันได้ยินมาว่ามันเป็นที่ถกเถียงกันอยู่ว่าคอลัมน์ Nullable โดยทั่วไปนั้นทำลายระดับแรกของการทำให้เป็นมาตรฐาน แต่ในทางปฏิบัติมันใช้ได้จริง


3
คอลัมน์ Nullable สามารถอยู่ใน 1NF ถึง 5NF แต่ไม่ใช่ใน 6NF ตามสิ่งที่ฉันอ่าน
Walter Mitty

-1

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

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