foreign key สามารถเป็น NULL และ / หรือทำซ้ำได้หรือไม่?


325

โปรดอธิบายสองสิ่งให้ฉัน:

  1. foreign key สามารถเป็นค่า NULL ได้หรือไม่?
  2. รหัสต่างประเทศสามารถทำซ้ำได้หรือไม่

ยุติธรรมเท่าที่ฉันรู้NULLไม่ควรใช้ในคีย์ต่างประเทศ แต่ในบางแอปพลิเคชันของฉันฉันสามารถป้อนข้อมูลNULLทั้งใน Oracle และ SQL Server และฉันไม่รู้ว่าทำไม


1
@ เอเดรีย: ที่ดีที่สุดของความรู้ของฉันที่สำคัญต่างประเทศไม่สามารถเป็นโมฆะ แต่มันจะเป็นโมฆะใน SQL Server และ Oracle คุณอธิบายได้ไหม
แยม

@Jams - อ่านลิงก์ในคำตอบของฉัน
JNK

11
ไม่สามารถลบได้เพราะคำตอบและคำถามนั้นมีประโยชน์ อย่าลังเลที่จะแก้ไขคำถามเพื่อปรับปรุง
Jeff Atwood

โปรดแยกคำถามเกี่ยวกับรายการที่ซ้ำกัน มีเพียงหนึ่งคำตอบเกี่ยวกับ NULL เท่านั้นที่ได้รับคำตอบด้านล่าง
reinierpost

คำตอบ:


529

คำตอบสั้น ๆ : ใช่มันสามารถเป็นค่า NULL หรือซ้ำได้

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

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

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

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


13
ดังนั้นจึงตั้งใจว่าจะดีกว่าการมีพนักงานขายปลอมชื่อ "ไม่ได้กำหนด"
Thomas Weller

8
ความคิดเห็น. Nulls ออกจากพื้นที่จำนวนมากเพื่อหาข้อผิดพลาดในแบบสอบถามโดยผู้ที่ไม่รู้ว่า SQL (mis) จัดการ 3VL อย่างไร หากพนักงานขายไม่จำเป็นสำหรับตาราง r-box อย่างแท้จริงคุณเพียงแค่ไม่รวมระเบียนนั้น ตารางแยกต่างหากสามารถเป็น "ProposalAssignedTo" หรือบางอย่างเช่นมีข้อ จำกัด ที่เหมาะสม ผู้เขียนแบบสอบถามสามารถเข้าร่วมตารางนั้นและระบุเหตุผลของตนเองสำหรับสิ่งที่เราต้องการทำเมื่อข้อเสนอไม่มีพนักงานขาย NULL ไม่เพียง แต่หมายถึง "เราไม่รู้" - สามารถใช้กับสิ่งต่าง ๆ ได้มากมาย (ซึ่งเป็นเหตุผลว่าทำไมมันจึงเป็นความคิดที่เลว)
N West

26
@nWest ฉันไม่อนุญาตให้ผู้ที่ไร้ความสามารถในการสืบค้นฐานข้อมูลของฉันและผู้พัฒนาที่ไม่รู้วิธีจัดการ nulls จะไร้ความสามารถ มีบางครั้งที่ข้อมูลไม่เป็นที่รู้จักในเวลาของการป้อนข้อมูลเริ่มต้นสำหรับเขตข้อมูลเฉพาะ แต่ฟิลด์อื่น ๆ ที่จำเป็นในเวลานั้น
HLGEM

28
@ThomasWeller การอ้างอิงพนักงานขายปลอม ("ไม่ได้กำหนด") ทำให้ปัญหาแย่ลง ฉันคิดว่าตารางพนักงานขายของคุณมีหลายคอลัมน์ ... ? หมายเลขประกันสังคมของนาย Unassigned คืออะไร? แผนกใดที่เขามอบหมายให้ เจ้านายของเขาคือใคร ฉันหวังว่าคุณจะได้รับคะแนนของฉัน: เมื่อคุณสร้างพนักงานขาย "ไม่ได้รับมอบหมาย" คุณจะพบว่าคุณทำการซื้อขายNULLในหลาย ๆNULLตารางในตารางที่แตกต่างกันอย่างรวดเร็ว
Gili

1
@ThomasWeller คุณจะมีปัญหาหาก / เมื่อคุณต้องการ จำกัด อินเทอร์เฟซของคุณ
tobiv


45

จากปากม้า:

คีย์ต่างประเทศอนุญาตให้ค่าคีย์ที่เป็น NULL ทั้งหมดแม้ว่าจะไม่มีคีย์หลักหรือ UNIQUE ที่ตรงกัน

ไม่มีข้อ จำกัด ในคีย์ต่างประเทศ

เมื่อไม่มีข้อ จำกัด อื่น ๆ ถูกกำหนดบน foreign key จำนวนแถวใด ๆ ในตาราง child สามารถอ้างอิงค่า parent key เดียวกันได้ รุ่นนี้อนุญาตให้มีค่า Null ใน foreign key ...

ไม่เป็นโมฆะข้อ จำกัด ในคีย์ต่างประเทศ

เมื่อไม่อนุญาตให้ใช้ค่า null ใน foreign key แต่ละแถวในตาราง child ต้องอ้างอิงค่าใน parent key อย่างชัดเจนเนื่องจากไม่อนุญาตให้มีค่า null ใน foreign key

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

ข้อ จำกัด ที่ไม่ซ้ำกับรหัสต่างประเทศ

เมื่อข้อ จำกัด UNIQUE ถูกกำหนดไว้บน foreign key เพียงหนึ่งแถวในตารางลูกสามารถอ้างอิงค่า parent key ที่กำหนดได้ รุ่นนี้อนุญาตให้มีค่า Null ใน foreign key

โมเดลนี้สร้างความสัมพันธ์แบบหนึ่งต่อหนึ่งระหว่างพาเรนต์และคีย์ต่างประเทศที่อนุญาตค่าที่ไม่ได้ระบุ (null) ในคีย์ต่างประเทศ ตัวอย่างเช่นสมมติว่าตารางพนักงานมีคอลัมน์ชื่อ MEMBERNO อ้างอิงถึงหมายเลขสมาชิกพนักงานในแผนประกัน บริษัท นอกจากนี้ตารางที่ชื่อ INSURANCE มีคีย์หลักชื่อ MEMBERNO และคอลัมน์อื่น ๆ ของตารางจะเก็บข้อมูลตามลำดับที่เกี่ยวข้องกับนโยบายการประกันพนักงาน MEMBERNO ในตารางพนักงานจะต้องเป็นทั้ง foreign key และ key ที่ไม่ซ้ำกัน:

  • เพื่อบังคับใช้กฎความสมบูรณ์ของ Referential ระหว่างตาราง EMP_TAB และ INSURANCE (ข้อ จำกัด ของคีย์ต่างประเทศ)

  • เพื่อรับประกันว่าพนักงานแต่ละคนมีหมายเลขสมาชิกที่ไม่ซ้ำกัน (ข้อ จำกัด คีย์ UNIQUE)

ข้อ จำกัด และไม่เป็นโมฆะในคีย์ต่างประเทศ

เมื่อมีการกำหนดทั้งข้อ จำกัด UNIQUE และ NOT NULL ไว้บน foreign key เพียงหนึ่งแถวในตารางลูกสามารถอ้างอิงค่า parent key ที่กำหนดและเนื่องจากค่า NULL ไม่ได้รับอนุญาตใน foreign key แต่ละแถวในตารางลูกต้องอ้างอิงอย่างชัดเจน ค่าในคีย์หลัก

ดูนี่:

ลิงค์ Oracle 11g


16

ใช่รหัสต่างประเทศสามารถเป็นโมฆะตามที่ได้บอกไว้ข้างต้นโดยโปรแกรมเมอร์อาวุโส ... ฉันจะเพิ่มสถานการณ์อีกครั้งที่รหัสต่างประเทศจะต้องเป็นโมฆะ .... สมมติว่าเรามีความคิดเห็นของตารางรูปภาพและวิดีโอในแอปพลิเคชัน วิดีโอ ในตารางความคิดเห็นเราสามารถมี PicturesId ของ Foreign Keys สองอันและ VideosId พร้อมกับ KeyId หลักของ CommentId ดังนั้นเมื่อคุณแสดงความคิดเห็นในวิดีโอเฉพาะ VideosId เท่านั้นที่จะต้องใช้และ pictureId จะเป็นโมฆะ ... และถ้าคุณแสดงความคิดเห็นในรูปภาพเท่านั้นต้องใช้ PictureId และ VideosId จะเป็นโมฆะ ...


1
ฉันคิดว่ามีวิธีที่ดีกว่าในการแก้ปัญหานี้ แทนที่จะสร้างคอลัมน์ใหม่คุณสามารถมีสองคอลัมน์คือ "id" และ "type" ซึ่งจะมี id และชื่อของตารางคีย์ต่างประเทศ เช่น id = 1, type = รูปภาพจะแสดงลิงค์ไปยังตารางรูปภาพที่มี id 1 ข้อดีของการใช้วิธีนี้คือคุณไม่จำเป็นต้องสร้างคอลัมน์ใหม่เมื่อมีการเพิ่มความคิดเห็นในตารางเพิ่มเติม ข้อเสียจะไม่มีข้อ จำกัด foreign key ในระดับ db แต่ข้อ จำกัด จะต้องเป็นระดับแอป
Agent47DarkSoul

4
@Agent: เรามี "วิธีแก้ปัญหา" นี้ในการใช้งานจริง อย่าทำมันมันแย่มาก การสืบค้นจะกลายเป็นความยุ่งเหยิง "ถ้าเป็นประเภท 1 เข้าร่วมในตารางนี้มิฉะนั้นเข้าร่วมกับสิ่งนี้" มันเป็นฝันร้ายสำหรับเรา เราลงเอยทำสิ่งที่คำตอบนี้พูดและสร้างคอลัมน์ใหม่สำหรับการเข้าร่วมแต่ละประเภท การสร้างคอลัมน์มีราคาถูก ค่อนข้างมากข้อบกพร่องเพียงอย่างเดียวคือคอลัมน์จำนวนมากทำให้คางคกใช้ยาก แต่นั่นเป็นเพียงข้อบกพร่องของคางคก
user128216

1
@FighterJet Rails ให้กรอบ ORM ที่ยอดเยี่ยมซึ่งจัดการกับข้อความค้นหาที่ซับซ้อนด้วยโซลูชันนี้
Agent47DarkSoul

2
@Agent: อาจจะเป็น ... แต่ถ้าคุณสามารถทำให้มันง่ายทำไมทำให้มันซับซ้อน? และบางที "ฝันร้าย" เป็นคำที่ใช้ไม่ถูกต้อง: มันไม่สะดวก เราไม่ประสบปัญหาความถูกต้องของข้อมูล (มาก)
user128216

7

มันขึ้นอยู่กับบทบาทforeign keyของคุณในความสัมพันธ์ของคุณ

  1. ถ้าสิ่งนี้foreign keyเป็นkey attributeความสัมพันธ์ของคุณด้วยมันจะไม่เป็นค่า NULL
  2. ถ้านี่foreign keyเป็นคุณสมบัติปกติในความสัมพันธ์ของคุณก็สามารถเป็นโมฆะ

3

นี่คือตัวอย่างการใช้ไวยากรณ์ของ Oracle:
ขั้นแรกให้สร้างตาราง COUNTRY

CREATE TABLE TBL_COUNTRY ( COUNTRY_ID VARCHAR2 (50) NOT NULL ) ;
ALTER TABLE TBL_COUNTRY ADD CONSTRAINT COUNTRY_PK PRIMARY KEY ( COUNTRY_ID ) ;

สร้างตารางจังหวัด

CREATE TABLE TBL_PROVINCE(
PROVINCE_ID VARCHAR2 (50) NOT NULL ,
COUNTRY_ID  VARCHAR2 (50)
);
ALTER TABLE TBL_PROVINCE ADD CONSTRAINT PROVINCE_PK PRIMARY KEY ( PROVINCE_ID ) ;
ALTER TABLE TBL_PROVINCE ADD CONSTRAINT PROVINCE_COUNTRY_FK FOREIGN KEY ( COUNTRY_ID ) REFERENCES TBL_COUNTRY ( COUNTRY_ID ) ;

สิ่งนี้ทำงานได้อย่างสมบูรณ์แบบใน Oracle โปรดสังเกตว่ารหัสประเทศ COUNTRY_ID ในตารางที่สองไม่มี "ไม่เป็นโมฆะ"

ตอนนี้การแทรกแถวลงในตารางจังหวัดก็เพียงพอที่จะระบุ Province_ID เท่านั้น อย่างไรก็ตามหากคุณเลือกที่จะระบุ COUNTRY_ID เช่นนั้นจะต้องมีอยู่แล้วในตาราง COUNTRY


1

โดยค่าเริ่มต้นไม่มีข้อ จำกัด ในการที่สำคัญต่างประเทศที่สำคัญต่างประเทศสามารถเป็นโมฆะและซ้ำกัน

ในขณะที่สร้างตาราง / แก้ไขตารางหากคุณเพิ่มข้อ จำกัด ของความเป็นเอกลักษณ์หรือไม่เป็นโมฆะก็จะไม่อนุญาตให้มีค่า Null / ซ้ำกัน


0

เพียงแค่ใส่ความสัมพันธ์ "แบบไม่ระบุตัวตน" ระหว่างเอนทิตีเป็นส่วนหนึ่งของ ER-Model และมีอยู่ใน Microsoft Visio เมื่อออกแบบ ER-Diagram สิ่งนี้จำเป็นในการบังคับใช้ cardinality ระหว่างเอนทิตีของประเภท "ศูนย์หรือมากกว่าศูนย์" หรือ "ศูนย์หรือหนึ่ง" โปรดสังเกตว่า "ศูนย์" นี้มีความสำคัญเชิงลบแทนที่จะเป็น "หนึ่ง" ใน "หนึ่งต่อมาก"

ตอนนี้ตัวอย่างของความสัมพันธ์ที่ไม่ได้ระบุตัวตนที่ cardinality อาจเป็น "ศูนย์" (ไม่ใช่การระบุ) คือเมื่อเราพูดบันทึก / วัตถุในหนึ่งเอนทิตี A "อาจ" หรือ "อาจไม่" มีค่าเป็นการอ้างอิงบันทึก / s ใน Entity-B อื่น

เนื่องจากมีความเป็นไปได้สำหรับระเบียนหนึ่งของเอนทิตี A เพื่อระบุตัวเองไปยังระเบียนของเอนทิตีอื่น ๆ ดังนั้นจึงควรมีคอลัมน์ในเอนทิตี -B เพื่อให้มีเอกลักษณ์ค่าของเรคคอร์ดของเอนทิตี -B คอลัมน์นี้อาจเป็น "Null" หากไม่มีระเบียนใน Entity-A ระบุระเบียน / s (หรือวัตถุ / s) ใน Entity-B

ในกระบวนทัศน์ Object Oriented (โลกแห่งความเป็นจริง) มีสถานการณ์เมื่อวัตถุของคลาส B ไม่จำเป็นต้องขึ้นกับ (อย่างยิ่งคู่) ในวัตถุของคลาส A สำหรับการมีอยู่ของมันซึ่งหมายความว่า Class-B เป็นแบบคู่กับคลาส A ที่ Class-A อาจ "Contain" (Containment) วัตถุของ Class-A เมื่อเทียบกับแนวคิดของวัตถุของคลาส -B จะต้องมี (Composition) วัตถุของ Class-A สำหรับ (วัตถุของคลาส - B) การสร้าง

จากมุมมอง SQL Query คุณสามารถเคียวรีเร็กคอร์ดทั้งหมดในเอนทิตี -B ซึ่งเป็น "ไม่ใช่โมฆะ" สำหรับคีย์ต่างประเทศที่สงวนไว้สำหรับ Entity-B สิ่งนี้จะนำระเบียนทั้งหมดที่มีค่าที่สอดคล้องกันสำหรับแถวใน Entity-A หรือระเบียนทั้งหมดที่มีค่า Null จะเป็นระเบียนที่ไม่มีระเบียนใด ๆ ใน Entity-A ใน Entity-B


-1

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

แต่คำตอบคือทุกอย่างขึ้นอยู่กับธุรกิจ


-3

แนวคิดของ foreign key นั้นขึ้นอยู่กับแนวคิดของการอ้างอิงค่าที่มีอยู่แล้วในตารางหลัก นั่นคือสาเหตุที่มันถูกเรียกว่า foreign key ในตารางอื่น แนวคิดนี้เรียกว่า Referential Integrity หากมีการประกาศคีย์ต่างประเทศเป็นฟิลด์ว่างจะเป็นการละเมิดตรรกะของการอ้างอิงที่สมบูรณ์ มันจะหมายถึงอะไร? มันสามารถอ้างถึงสิ่งที่มีอยู่ในตารางหลักเท่านั้น ดังนั้นฉันคิดว่ามันจะผิดที่จะประกาศเขตข้อมูลคีย์ต่างประเทศเป็นโมฆะ


มันสามารถอ้างอิง "ไม่มีอะไร" หรือคุณยังไม่ทราบคุณค่าของมันNULLแต่สิ่งที่ Referential Integrity พูดก็คือถ้ามันอ้างอิงถึง "อะไร" มันต้องอยู่ที่นั่น
yaxe

-7

ฉันคิดว่า foreign key ของตารางหนึ่งเป็นคีย์หลักของตารางอื่นด้วยดังนั้นจะไม่อนุญาตให้มีค่า null ดังนั้นจึงไม่มีคำถามว่าค่า null เป็นคีย์ต่างประเทศ

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