LoginSignup

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

主キーに変更される可能性のある列を入れるべきか

例えば以下の様なDBテーブルがあります。

CREATE TABLE Member
(
    ID INT IDENTITY PRIMARY KEY,
    Name NVARCHAR(10),
    Status TINYINT,   
    CONSTRAINT UN_MainNameStatus UNIQUE(Name, Status)   
)

CREATE TABLE Info
(
    Name NVARCHAR(10),
    Status TINYINT,
    InfoNunber INT,
    InfoBody NVARCHAR(50),
    PRIMARY KEY(Name, Status, InfoNunber)
)

ここで、MemberテーブルのStatusは更新される可能性があります。また、InfoNameStatusはプログラムレベルで一致させています。問題は現状だとMemberStatus更新時にInfoの古いデータを削除し、新しいステータスに変更したコピーデータを代入しなければならない点です。この場合、Infoの主キーのNameStatusIDに変更すれば外部キー制約が利用できるようになり、Memberテーブルと同時に更新する必要(データ破壊のリスク)が無くなり、DB更新も速くなると思うのですが、いかがでしょうか。

0

InfoテーブルのName列とStatus列をIDに置き換えても構わないのなら、置き換えたほうが良いと思う。

さらにいうと、私はサロゲートキー原理主義なので、IDMemberIDを用意し、Member.IDInfo.MemberIDで外部制約を組み、Info.IDは主キーとしての責務に励んでもらいます(過激派)。

1Like

InfoNameStatusMemberの同項目と同じ値に保ちたいのであれば、外部制約を作成してON UPDATE CASCADEを指定すれば出来るでしょう。

それとは別に、更新される項目を主キーに含めるのは避けた方が良いでしょう。
データベース側の視点としては主キーのインデックスの再構成が走ることになりパフォーマンス面でよくありませんし、
アプリゲーション側の視点では、ORM等を利用する場合に問題が出る場合があります。
例えば、EntityFrameworkを利用した場合に自動的にUPDATE処理の実装が作成されますが、主キーが更新されることを想定していないので主キーを更新する場合に自動生成処理は利用できません(生SQLを発行して独自に更新処理を用意する必要が出てきます)。
同様に、DBから自動的にSQLを生成するようなフレームワークを利用する場合も生成されたSQLがそのまま利用できないことも考えられます。
(多くのフレームワークでは主キーを更新することはBad Practice扱いです)

@ktz_alias さんが言っていますが、IDを利用できるのであればIDを利用するのが無難でしょう。

0Like

Infoはマスターテーブルですか?
それともMember1レコードにつきInfo1レコードを持つ形式?

0Like

まぜっかえすようなコメントで申し訳ないのですが、しっかりしたテーブル設計(データモデリング)ができていれば、主キーを構成する列にUpdateが発生することは、基本的にないはずです。(Inser/Deleteしか発生しないのが基本)
ですので、「主キーに変更される可能性のある列を入れるべきか」ではなく、「なぜ主キーに更新が発生する設計になっているか」を考え、修正すべきです。

提示いただいた情報からだけでは、どういう業務モデルを想定しているのかわかりませんが、少なくとも、「Member」というテーブルの主キーが「Name」と「Status」で構成されるのはおかしいです。
(NameとStatusでユニークキーを構成しているのは、これが論理的な主キー(ビジネスキー)だという意味であっていますよね?)
おかしい理由は、Memberというテーブルは、その名称から考えて、メンバー1名が1レコードになるテーブルであるはずなのに、1名に対してStatusの分、複数レコードが生成されてしまうこと、です。

想定している業務モデル次第ですが、たとえば、以下のような設計が修正案になりうるかと思います。

CREATE TABLE Member
(
    Name NVARCHAR(10),
    Birthday date,
    Gender int,
    CONSTRAINT PK_Member PRIMARY KEY(Name)   
)
CREATE TABLE MemberStaus
(
    Name NVARCHAR(10),
    Status TINYINT,
    CONSTRAINT PK_MemberStatus PRIMARY KEY(Name, Status)   
)

CREATE TABLE MemberAttribute
(
    Name NVARCHAR(10),
    AttributeType INT,
    AttributeValue NVARCHAR(50),
    CONSTRAINT PK_UserAttribute PRIMARY KEY(Name, AttributeType)   
)

ID列(サロゲートキー)の話は、この辺りを整理した後で、考えればよいかと。

0Like

Your answer might help someone💌