web-dev-qa-db-ja.com

主キー保証:重複と無効

Oracleでは、主キーが重複したnull値を持つことを許可しています。この機能を使用することは特に良い考えではありませんが、ほとんどの開発者が主キーの保証(null以外、一意)を考慮しているものの一部は、実際の保証ではないことを意味します。

CREATE TABLE Oracle_guarantees (
    ID NUMBER(9,0),
    NAME VARCHAR2(50 BYTE),
    breed NVARCHAR2(100)
);

INSERT INTO Oracle_guarantees VALUES (1, 'Fuzz Head', 'Tabby');
INSERT INTO Oracle_guarantees VALUES (2, 'Fluffy Thing', 'Mix');
INSERT INTO Oracle_guarantees VALUES (2, 'Fluffy Thing', 'Mix');
INSERT INTO Oracle_guarantees VALUES (3, 'Tiger', 'Tabby');
INSERT INTO Oracle_guarantees VALUES (4, 'Fur Beast', 'Bengal');
INSERT INTO Oracle_guarantees VALUES (5, 'Karate', 'Japanese Bobtail');
INSERT INTO Oracle_guarantees VALUES (6, 'Chairman Meow', 'Chinese Harlequin');
INSERT INTO Oracle_guarantees VALUES (NULL, 'No Cat', 'No breed');

CREATE INDEX Oracle_guarantees_pk ON Oracle_guarantees (ID);
ALTER TABLE Oracle_guarantees ADD CONSTRAINT Oracle_guarantees_pk PRIMARY KEY (ID) DISABLE KEEP INDEX;
ALTER TABLE Oracle_guarantees MODIFY CONSTRAINT Oracle_guarantees_pk ENABLE NOVALIDATE;

SQLite PKも1つのnullを許可しますが、重複する値は許可しません

Microsoft SQLまたはPostgresで重複する値またはnull値を持つ主キーとしてマークされた制約を持つことは可能ですか?

言い換えれば、ドキュメント化された機能セット内のPKの一意性とnull以外に完全に依存できますか(手動で編集されたデータファイル、バグ、または変更されたサーバーソースコードなどのケースは無視します)。


さらに明確化:DBAと開発者は、私が思っていたよりも少し異なる動作をしていると思います。

考察の演習:開発者は、anyテーブルの行を一意に識別する必要があります(テーブル構造はコンパイル時には不明です)。 主キー制約に関するOracleのドキュメント が検索で表示され、次のように述べられています。

主キー制約は、NOT NULL制約と一意制約を1つの宣言で組み合わせたものです。つまり、複数の行が同じ列または列の組み合わせに同じ値を持つことを禁止し、値がnullになることを禁止します。

次に、開発者は実行時に任意のテーブルの主キーを見つける手段を探します。彼らはおそらくこのような質問に遭遇します: https://stackoverflow.com/questions/9016578/how-to-get-primary-key-column-in-Oracle

投票数の多い回答のクエリは次のようになります。

Results of PK metadata query

この時点で、合理的なDBA以外の人は、ID列にNULLまたは重複する値を含めることはできないと結論付けていると思います。この結論は真実ではありません。

  • オラクルのせいですか?番号。
  • テーブルは適切に設計されていますか?番号。
  • そのようなテーブルを作成するステートメントは複雑ですか? 重要ではありません。
  • Id列は「実際の」主キーですか?そうではないかもしれませんが、これはより哲学的な問題です。 IDisは、クエリによって上位のSO上記のリンクされた質問。おそらくその質問は検証のチェックを追加する必要があるかもしれませんが、コードでこれをチェックする人を見たことがなく、そのスレッドまたは私が見つけた関連するスレッドで回答もしていません。

エルゴ、実社会では、任意のテーブルが重複した値を持つ(all_constraints.constraint_typeの定義により)主キーを持つことができます。そしてNULL値。

ソフトウェアはまた、制約が検証されていることを確認する必要があることを知っています。優れた!それは私が必要とする保証を提供します。

問題は、PostgreSQLまたはMicrosoft SQLでNULLまたは重複する値を持つ主キー(DBMSメタデータで定義されている)を持つことは可能ですか?

3
Charles Burns

Oracleでは、主キーが重複したnull値を持つことを許可しています。

あんまり。一連の複雑なステートメントの後に作成したものは、有効ですが検証されていない制約です。つまり、Oracleは挿入と更新を(一意性について)チェックしますが、既存の重複が残っている可能性があります。つまり、名前だけのPKです。これは検証されていない制約なので、実際にはPKではありません。

言い換えれば、ドキュメント化された機能セット内のPKの一意性とnull以外に完全に依存できますか(手動で編集されたデータファイル、バグ、または変更されたサーバーソースコードなどのケースは無視します)。

より多くのコンテキスト:私は、レコードを表示し、ユーザーが任意のテーブルでそれらを削除できるアプリケーションに取り組んでいます。任意のテーブルを処理する場合、メタデータやその他の手段を使用して、どの保証があるかを判断する必要があります。多くのデータベース開発は保証についてです-大規模なトランザクションがコミットするかしないかを保証します(ただし、部分的にはコミットしません)。正常に変更された行が変更されたままであることを保証します。また、主キーが一意に正確に1行を参照することを保証します。

はい、信頼できますが、アプリケーションがメタデータとすべての詳細を読み取る場合に限ります-DBMSごとに異なる場合があります。

  • SQL Serverでは、制約を無効にできますか?アプリケーションは、メタデータテーブルを読み取って解釈するときにこれを考慮する必要があります。

  • Oracleは、無効または検証されていない制約を許可しますか?アプリケーションは、これらのオプションもそれに応じて考慮する必要があります。

  • Postgresはいくつかの異なる奇妙なシナリオを可能にしますか?それらも考慮する必要があります。

別の可能なオプション-オプションである場合もない場合もあります-アプリケーションが、データベースオブジェクトを作成、削除、変更する唯一のアプリケーションであるか、それを行うすべてのアプリケーションがユーザーまたは単一の制御下にある場合です。次に、これらの詳細/まれなケースをチェックすることなく、メタデータの健全性に依存する(「一意の制約のみを考慮する」)ことができます。これは、そもそもそのようなまれなケースが作成されないことを信頼できるためです。

あなたの結論で:

オラクルのせいですか?番号。

同意する。これが許可された理由はわかりませんが、おそらくいくつかの問題は解決します。そしてそれはおそらく一時的にのみ使用されることを意図していた-例えば別のソースからデータベースへのインポート中。

テーブルは適切に設計されていますか?番号。

そのようなテーブルを作成するステートメントは複雑ですか?重要でない。

私も両方に同意します。

Id列は「実際の」主キーですか?そうではないかもしれませんが、これはより哲学的な問題です。 IDは、クエリによって上位のSO上記のリンクされた質問への回答に表示されます( "ENABLED"として表示されます)。おそらく、その質問には検証用のチェックを追加する必要がありますが、コードでこれをチェックする人を見たことは一度もありません。また、そのスレッドまたは私が見つけた関連スレッドで回答を行ったこともありません。

同じ結論になります:検証のチェックを追加する必要があります。


SQL ServerとPostgresには他にどのような可能性がありますか。

  • SQLサーバー:

    • PRIMARY KEYおよびUNIQUE制約は無効にできません
    • 一意のインデックスを無効にできます。また、チェックなしで再度有効にすることもできます。これは、Oracleの「有効な非検証済み」と非常によく似た状況になります。
    • FOREIGN KEYおよびCHECK制約は無効にできます。チェックなしで再度有効にすることもできます
      詳細については ALTER TABLE および インデックスと制約を無効にする を参照してください。この質問に対する私の回答: WITH CHECK CHECK CONSTRAINT?とは は、Oracleとは異なるオプションと構文について説明しています。
  • PostgreSQL:

    • PRIMARY KEYUNIQUEおよびEXCLUDE制約は無効にできません
    • FOREIGN KEYおよびCHECK制約は無効にできません。それらはNOT VALIDオプションで作成できます(つまり、SQL Serverのように既存の行をチェックせずに有効化されます)。詳細は ALTER TABLE を参照してください。
6
ypercubeᵀᴹ

SQL Server内では、 primary key はオブジェクトの範囲内で一意であり、null値を含めることはできません(実際には、列をプライマリで使用するには、null以外の制約で作成する必要がありますキー)。

一意の制約 を作成することが可能です。これは一意になりますが、null値も許可します。

2
Nic

引用 主キーに関するPostgreSQLドキュメント

5.3.4。主キー

主キー制約は、列または列のグループをテーブル内の行の一意の識別子として使用できることを示します。これには、値が一意であり、nullではないことが必要です。したがって、次の2つのテーブル定義は同じデータを受け入れます

[...]

主キーを追加すると、主キーにリストされている列または列のグループに一意のBツリーインデックスが自動的に作成され、列が強制的にNOT NULLとマークされます。

したがって、実際には、MS SQL Serverに同意します。および 2008 SQL Standard(2006年からのドラフト)

主キー制約は、PRIMARY KEYを指定する一意の制約です。主キー制約が満たされるのは、テーブル内の2つの行が一意の列に同じ非null値を持たず、指定された1つまたは複数の列の値がnull値でない場合だけです。

2
joanolo