Bir boş sütun birincil anahtarın parçası olabilir mi?


15

Bir SQL Server 2012 veritabanı geliştiriyorum ve bir-bir-sıfır-veya-bir ilişkisi hakkında bir sorum var.

İki masam var Codesve HelperCodes. Bir kodun sıfır veya bir yardımcı kodu olabilir. Bu, bu iki tabloyu ve ilişkilerini oluşturmak için sql betiğidir:

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])
)

Bu doğru mu?

Kod ve HelperCode her ikisi de farklı varlıklardır. Bir HelperCode kullanılmış (hiçbir Kod ona referans vermez) veya kullanılabilir (yalnızca bir Kod ona atıfta bulunabilir) olabilir.

Belki Code.HelperCodeId, Kod tablosu birincil anahtarının bir parçası olmalıdır. Ancak, boş bir sütunun birincil sütunun bir parçası olup olmayacağından emin değilim. Bunu yaparken, iki veya daha fazla Kod aynı HelperCode başvurmak önlemek istiyorum.


1
Neden HelperCodeIdPK'nin bir parçası olmak istesin ? İki veya daha fazla Kodun aynı HelperCode'a referansta bulunmasını önlemek istediğiniz için herhangi bir şans var mı?
Andriy M

Evet, iki veya daha fazla kodun aynı HelperCode'a başvurmasını önlemek istiyorum. Başka bir seçenek de HelperCodeIdsütunu Benzersiz olarak ayarlamaktır .
VansFannel

@ypercube Lütfen sql cümlesinin tamamını cevap olarak ekler misiniz? Sql ile çok sık çalışmıyorum ve nasıl yapılacağını bilmiyorum. Teşekkürler.
VansFannel

Kavramsal olarak, DBMS mühendisleri ilişkisel veri modelinin tamamına karşı çıkmadan birincil anahtarlarda NULL'lara izin veremezdi. İlişkisel model, ilişkisel veritabanlarını bu kadar kullanışlı kılan şeyin bir parçasıdır. Bu yönüyle ilgilenebilir veya ilgilenmeyebilirsiniz, ancak gelecekteki ziyaretçiler için dikkat çekmek önemlidir.
Walter Mitty

@WalterMitty Bir PK'de null değere sahip olmanın neden RDBMS'nin getirdiği değeri yok edeceğini hiç anlamadım. Bunu birçok kez duydum. Detaylandırabilir misin?
usr

Yanıtlar:


24

Başlıktaki soruyu cevaplamak için, hayır, tüm birincil sütunların olması gerekir NOT NULL.

Ancak, tabloların tasarımını değiştirmeden Code (HelperCodeId)sütuna filtrelenmiş bir dizin ekleyebilirsiniz :

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

Filter ( WHERE HelperCodeId IS NOT NULL) yöntemi, SQL-Server'ın benzersiz kısıtlamalarda ve benzersiz dizinlerde boş değerleri işleme biçimi nedeniyle gereklidir. Filtre olmadan, SQL Sunucu ile birden fazla satır izin vermeyeceğini NULLde HelperCodeId.


Alternatif bir tasarım - HelperCodeIddan kaldırmak Codeve Code- HelperCodeilişkilerini saklayacak üçüncü bir tablo eklemek olacaktır . İki varlık arasındaki ilişki Sıfır veya Bire Bir Sıfır veya Bir gibi görünmektedir (hem Kodda HelperCode olamaz, hem de HelperCode Kodsuz kullanılabilir):

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 değişmeden kalır:

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])
) ;

Ek tabloda, UNIQUEher Kodun (maksimum) bir HelperCode ile ve her HelperCode'un (maksimum) bir Kod ile ilişkili olduğundan emin olmak için iki kontrast (veya bir birincil ve bir benzersiz) olacaktır. Her iki sütun da şöyle olur 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])
) ;

Teşekkürler, isterseniz tasarımı değiştirebilirsiniz. Çok şey öğrenebilirim.
VansFannel

Tasarımınız için teşekkürler. Yeni bir tablo eklemedim çünkü bu tabloların sadece çoktan çoğa ilişkide kullanıldığını düşündüm.
VansFannel

0

Bunun yerine benzersiz bir kısıtlama kullanmayı deneyin. Sözde ANSI standardı geçersiz olduğunu birincil anahtar olarak geçersiz ilan etti, ancak standardı hiç görmedim ve bunu doğrulamak için satın almak istemiyorum.

Boş anahtarlara sahip olmamak, geliştiricilerin şu ya da bu şekilde çok sert bir inanca sahip oldukları şeylerden biri gibi görünüyor. Benim tercihim onları kullanmak çünkü ben doldurulmamış açılan kutuları için araç ipuçları ve ilgili verileri içeren arama tabloları için yararlı buluyorum.

Boş değerin bir değişkenin hiç ayarlanmadığını ve boş değerin değerin geçmişte ayarlandığını gösterdiğini öğrendim. Tabii ki bu uygulama için tanımlamak için geliştiriciye kalmış, ancak boş birincil anahtarlara izin vermenin saçma olduğunu düşünüyorum, ancak boş birincil anahtarlara değil.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.