คอลัมน์ null อาจเป็นส่วนหนึ่งของคีย์หลักได้หรือไม่


15

ฉันกำลังพัฒนาฐานข้อมูล SQL Server 2012 และฉันมีคำถามเกี่ยวกับความสัมพันธ์แบบหนึ่งต่อศูนย์หรือหนึ่งวัน

ฉันมีสองตารางและCodes HelperCodesรหัสอาจมีรหัสศูนย์หรือหนึ่งตัวช่วย นี่คือสคริปต์ sql เพื่อสร้างสองตารางและความสัมพันธ์:

CREATE TABLE [dbo].[Code]
(
    [Id] NVARCHAR(20) NOT NULL, 
    [Level] TINYINT NOT NULL, 
    [CommissioningFlag] TINYINT NOT NULL, 
    [SentToRanger] BIT NOT NULL DEFAULT 0, 
    [LastChange] NVARCHAR(50) NOT NULL, 
    [UserName] NVARCHAR(50) NOT NULL, 
    [Source] NVARCHAR(50) NOT NULL, 
    [Reason] NVARCHAR(200) NULL, 
    [HelperCodeId] NVARCHAR(20) NULL,
    CONSTRAINT [PK_Code] PRIMARY KEY CLUSTERED
    (
        [Id] ASC
    ),
    CONSTRAINT [FK_Code_LevelConfiguration]
       FOREIGN KEY ([Level])
        REFERENCES [dbo].[LevelConfiguration] ([Level]),
    CONSTRAINT [FK_Code_HelperCode]
       FOREIGN KEY ([HelperCodeId])
        REFERENCES [dbo].[HelperCode] ([HelperCodeId])
)

CREATE TABLE [dbo].[HelperCode]
(
    [HelperCodeId] NVARCHAR(20) NOT NULL, 
    [Level] TINYINT NOT NULL, 
    [CommissioningFlag] TINYINT NOT NULL, 
    [LastChange] NVARCHAR(50) NOT NULL,
    CONSTRAINT [PK_HelperCode] PRIMARY KEY CLUSTERED
    (
        [HelperCodeId] ASC
    ),
    CONSTRAINT [FK_HelperCode_LevelConfiguration]
       FOREIGN KEY ([Level])
        REFERENCES [dbo].[LevelConfiguration] ([Level])
)

ถูกต้องหรือไม่

รหัสและ HelperCode เป็นเอนทิตีที่ต่างกัน HelperCode สามารถใช้งานได้ (ไม่มีรหัสอ้างอิงเลย) หรือใช้ (ใช้รหัสอ้างอิงได้เพียงรหัสเดียว)

บางที Code.HelperCodeId ต้องเป็นส่วนหนึ่งของรหัสหลักของตารางรหัส แต่ฉันไม่แน่ใจว่าคอลัมน์ว่างอาจเป็นส่วนหนึ่งของคอลัมน์หลักได้หรือไม่ เมื่อต้องการทำเช่นนี้ฉันต้องการป้องกันไม่ให้สองหรือมากกว่ารหัสอ้างอิง HelperCode เดียวกัน


1
ทำไมคุณต้องการHelperCodeIdเป็นส่วนหนึ่งของ PK? เป็นเพราะโอกาสใด ๆ เพราะคุณต้องการป้องกันสองรหัสขึ้นไปเพื่ออ้างอิง HelperCode เดียวกัน
Andriy M

ใช่ฉันต้องการป้องกันไม่ให้รหัสสองตัวหรือมากกว่านั้นอ้างอิง HelperCode เดียวกัน อีกทางเลือกหนึ่งคือการตั้งค่าHelperCodeIdคอลัมน์เป็นไม่ซ้ำ
VansFannel

@ypercube คุณช่วยเพิ่มประโยค sql ที่สมบูรณ์เป็นคำตอบได้ไหม? ฉันไม่ค่อยได้ทำงานกับ sql บ่อยนักและฉันก็ไม่รู้จะทำยังไง ขอบคุณ
VansFannel

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

@WalterMitty ฉันไม่เคยเข้าใจว่าทำไมการมีค่า Null ใน PK จะทำลายค่าที่ RDBMS นำมา ฉันเคยได้ยินหลายครั้ง คุณสามารถทำอย่างละเอียด?
usr

คำตอบ:


24

NOT NULLที่จะตอบคำถามในชื่อที่ไม่มีทุกคอลัมน์หลักจะต้องมีการ

แต่หากไม่มีการเปลี่ยนแปลงการออกแบบตารางคุณสามารถเพิ่มดัชนีที่กรองแล้วในCode (HelperCodeId)คอลัมน์:

CREATE UNIQUE INDEX 
    FUX_Code_HelperCodeId
ON dbo.Code 
    (HelperCodeId) 
WHERE 
    HelperCodeId IS NOT NULL ;

WHERE HelperCodeId IS NOT NULLจำเป็นต้องใช้ตัวกรอง ( ) เนื่องจากวิธีที่ SQL-Server ใช้เป็นโมฆะในข้อ จำกัด เฉพาะและดัชนีเฉพาะ โดยไม่ต้องกรองแบบ SQL Server ที่จะไม่อนุญาตให้มากกว่าหนึ่งแถวที่มีในNULLHelperCodeId


การออกแบบทางเลือกจะเป็นการลบHelperCodeIdจากCodeและเพิ่มตารางที่สามที่จะเก็บCode- HelperCodeความสัมพันธ์ ความสัมพันธ์ระหว่างเอนทิตี้ทั้งสองดูเหมือนจะเป็นศูนย์หรือหนึ่งไปสู่ศูนย์หรือทั้งสอง (โค้ดไม่สามารถมี HelperCode และ HelperCode อาจใช้โดยไม่มีโค้ด):

CREATE TABLE [dbo].[Code]
(
    [Id] NVARCHAR(20) NOT NULL, 
    [Level] TINYINT NOT NULL, 
    [CommissioningFlag] TINYINT NOT NULL, 
    [SentToRanger] BIT NOT NULL DEFAULT 0, 
    [LastChange] NVARCHAR(50) NOT NULL, 
    [UserName] NVARCHAR(50) NOT NULL, 
    [Source] NVARCHAR(50) NOT NULL, 
    [Reason] NVARCHAR(200) NULL, 
    -- 
    -- removed:   [HelperCodeId] NVARCHAR(20) NULL,
    -- 
    CONSTRAINT [PK_Code] PRIMARY KEY CLUSTERED
    (
        [Id] ASC
    ),
    CONSTRAINT [FK_Code_LevelConfiguration]
       FOREIGN KEY ([Level])
        REFERENCES [dbo].[LevelConfiguration] ([Level]),
) ;

HelperCode ยังคงไม่เปลี่ยนแปลง:

CREATE TABLE [dbo].[HelperCode]
(
    [HelperCodeId] NVARCHAR(20) NOT NULL, 
    [Level] TINYINT NOT NULL, 
    [CommissioningFlag] TINYINT NOT NULL, 
    [LastChange] NVARCHAR(50) NOT NULL,
    CONSTRAINT [PK_HelperCode] PRIMARY KEY CLUSTERED
    (
        [HelperCodeId] ASC
    ),
    CONSTRAINT [FK_HelperCode_LevelConfiguration]
       FOREIGN KEY ([Level])
        REFERENCES [dbo].[LevelConfiguration] ([Level])
) ;

ตารางเพิ่มเติมจะมีUNIQUEข้อ จำกัดสองข้อ (หรือหนึ่งข้อและหลักที่ไม่ซ้ำกัน) เพื่อให้แน่ใจว่าทุก Code เกี่ยวข้องกับ (สูงสุด) หนึ่ง HelperCode และ HelperCode แต่ละอันเกี่ยวข้องกับ (สูงสุด) หนึ่ง Code ทั้งสองคอลัมน์จะเป็นNOT NULL:

CREATE TABLE [dbo].[Code_HelperCode]
(
    [CodeId] NVARCHAR(20) NOT NULL, 
    [HelperCodeId] NVARCHAR(20) NOT NULL, 
    CONSTRAINT [UQ_Code_HelperCode_CodeId]
       UNIQUE (CodeId),
    CONSTRAINT [UQ_Code_HelperCode_HelperCodeId]
       UNIQUE (HelperCodeId),
    CONSTRAINT [FK_HelperCode_Code]
       FOREIGN KEY ([CodeId])
        REFERENCES [dbo].[Code] ([Id]),
    CONSTRAINT [FK_Code_HelperCode]
       FOREIGN KEY ([HelperCodeId])
        REFERENCES [dbo].[HelperCode] ([HelperCodeId])
) ;

ขอบคุณคุณสามารถแก้ไขการออกแบบได้ถ้าคุณต้องการ ฉันเรียนรู้ได้มาก
VansFannel

ขอบคุณสำหรับการออกแบบของคุณ ฉันไม่ได้เพิ่มตารางใหม่เพราะฉันคิดว่าตารางเหล่านี้ใช้เฉพาะในความสัมพันธ์แบบกลุ่มต่อกลุ่มเท่านั้น
VansFannel

0

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

การไม่มีคีย์ว่างใด ๆ ดูเหมือนจะเป็นหนึ่งในสิ่งเหล่านั้นที่นักพัฒนามีความเชื่อที่หนักหน่วงไม่ทางใดก็ทางหนึ่ง การตั้งค่าของฉันคือการใช้พวกเขาเพราะฉันคิดว่ามันมีประโยชน์สำหรับตารางการค้นหาที่มีคำแนะนำเครื่องมือและข้อมูลที่เกี่ยวข้องสำหรับ comboboxes ที่ไม่ได้รับการเติมข้อมูล

ฉันได้รับการสอนว่าค่า Null บ่งชี้ว่าไม่เคยมีการตั้งค่าตัวแปรและค่าว่างบ่งบอกว่าเคยตั้งค่าไว้แล้วในอดีต แน่นอนว่ามันขึ้นอยู่กับนักพัฒนาที่จะกำหนดแอพพลิเคชั่น แต่ฉันคิดว่ามันไร้สาระที่จะอนุญาตให้ใช้คีย์หลักที่ว่างเปล่า แต่ไม่ใช่คีย์หลักที่ว่างเปล่า

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