null列は主キーの一部になりますか?


15

SQL Server 2012データベースを開発していますが、One-to-Zero-Or-Oneの関係について質問があります。

2つのテーブルがCodesありHelperCodesます。コードには、ゼロまたは1つのヘルパーコードを含めることができます。これは、これら2つのテーブルとそれらの関係を作成する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])
)

あれは正しいですか?

CodeとHelperCodeは両方とも異なるエンティティです。HelperCodeは、使用(コードを参照するコードなし)または使用(コードを参照するコードは1つのみ)できます。

Code.HelperCodeIdは、コードテーブルの主キーの一部である必要があります。しかし、null列がプライマリの一部になる可能性があるかどうかはわかりません。これを行うと、2つ以上のコードが同じHelperCodeを参照するのを防ぐことができます。


1
なぜHelperCodeIdPKに参加したいのですか?2つ以上のコードが同じHelperCodeを参照するのを防ぎたいのですが、たぶんそうでしょうか?
アンドリーM

はい、2つ以上のコードが同じHelperCodeを参照しないようにします。別のオプションは、HelperCodeId列を一意として設定することです。
VansFannel

@ypercube完全なSQL文を答えとして追加してください。私はSQLを頻繁に使用せず、その方法がわかりません。ありがとう。
VansFannel

概念的には、DBMSエンジニアは、リレーショナルデータモデル全体に​​反することなく、プライマリキーにNULLを許可することはできませんでした。また、リレーショナルモデルは、リレーショナルデータベースを非常に便利にするものの一部です。あなたはこの側面に興味があるかもしれないし、そうでないかもしれませんが、将来の訪問者のために指摘することが重要です。
ウォルターミッティー

@WalterMitty PKにnull値があると、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 NULLSQL-Serverが一意の制約と一意のインデックスでnullを処理する方法のため、フィルター()が必要です。フィルターがなければ、SQL-ServerはNULLinを持つ複数の行を許可しませんHelperCodeId


別の設計では削除されるだろうHelperCodeIdからCodeと格納する第三のテーブルを追加Code- HelperCode関係を。2つのエンティティ間の関係は、ゼロまたはワンからゼロまたはワンのようです(コードには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、すべてのコードが(最大)1つのHelperCodeに関連付けられ、各HelperCodeが(最大)1つのコードに関連付けられるように、2つの制約(または1つのプライマリと1つの一意)があります。両方の列は次のようになります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標準は無効であるとプライマリキーとしてnullを宣言しましたが、私は標準を見たことがないので、これを確認するためにそれを購入したくありません。

nullキーを持たないことは、開発者が何らかの方法で非常に厳しい信念を持っていることの1つであると思われます。使用されないコンボボックスのツールチップと関連データを含むルックアップテーブルに役立つと思うので、私の好みはそれらを使用することです。

Null値は変数が設定されたことがないことを示し、空の値は値が過去に設定されたことを示すことを教えられました。もちろん、これはアプリケーション用に定義するのは開発者次第ですが、空の主キーは許可するがnullの主キーは許可しないのは無意味であると思います。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.