はじめに
データの保存は1つのことです。意味のある、便利な、正しいを保存する データはまったく別のものです。意味と有用性はそれ自体が主観的な性質ですが、正確さは少なくとも論理的に定義して実施することができます。タイプはすでに数値が数値で日付が日付であることを保証しますが、重みまたは距離が正の数値であることを保証したり、日付範囲が重複するのを防ぐことはできません。タプル、テーブル、およびデータベースの制約は、格納されているデータにルールを適用し、マスターを通過しない値または値の組み合わせを拒否します。
制約は、同じアサーションをテストする場合でも、他の入力検証手法を決して役に立たなくしません。無効なデータの保存の試行と失敗に費やされた時間は、無駄な時間です。 assert
などの違反メッセージ システムおよびアプリケーションプログラミング言語では、データベースのニーズに直接関与していない人よりもはるかに詳細に、最初の候補レコードの最初の問題を明らかにするだけです。しかし、データの正確性に関する限り、制約は、善悪を問わず、法則です。それ以外はアドバイスです。
タプルの場合:Null、デフォルト、およびチェックではありません
null以外の制約は、最も単純なカテゴリです。タプルは、constrained属性の値を持っている必要があります。言い換えると、列に許可されている値のセットには、空のセットが含まれていません。値がないということはタプルがないことを意味します。挿入または更新は拒否されます。
null値からの保護は、column_name COLUMN_TYPE NOT NULL
を宣言するのと同じくらい簡単です。 CREATE TABLE
またはADD COLUMN
。 null値は、データベースとエンドユーザーの間で問題のカテゴリ全体を引き起こすため、nullを許可する正当な理由なしに、任意の列にnull以外の制約を反射的に定義することは、良い習慣です。
何も指定されていない場合のデフォルト値の提供(省略または明示的なNULL
)候補レコードは拒否されるのではなく変更および保存されるため、挿入または更新では必ずしも制約とは見なされません。多くのDBMSでは、デフォルト値は関数によって生成される場合がありますが、MySQLではこの目的でユーザー定義関数を使用できません。
単一のタプル内の値のみに依存するその他の検証ルールは、CHECK
として実装できます。 制約。ある意味で、NOT NULL
それ自体はCHECK (column_name IS NOT NULL)
の省略形です。;違反して受信したエラーメッセージがほとんどの違いを生みます。 CHECK
ただし、単一のタプルに対して任意のブール述語の真理を適用および適用できます。たとえば、地理的な場所を格納するテーブルは、CHECK (latitude >= -90 AND latitude < 90)
である必要があります。 、および同様に-180〜180の経度の場合-または、可能な場合は、GEOGRAPHY
を使用して検証します データ型。
テーブル上:ユニークで除外
テーブルレベルの制約は、タプルを相互にテストします。一意性制約では、1つのレコードのみが、制約された列の任意の値のセットを持つことができます。 NULL
であるため、null可能性はここで問題を引き起こす可能性があります NULL
まで、他の何にも匹敵することはありません 自体。 (batman, robin)
に対する一意の制約 したがって、ロビンレスバットマンの無限のコピーが可能になります。
除外制約はPostgreSQLとDB2でのみサポートされていますが、非常に便利なニッチを埋めます。重複を防ぐことができます。制約されたフィールドとそれぞれが評価される操作を指定します。新しいレコードは、既存のレコードが各フィールドおよび操作と正常に比較されない場合にのみ受け入れられます。たとえば、schedules
競合を拒否するようにテーブルを構成できます:
-- text, int, etc. comparisons in exclusion constraints require this-- Postgres extensionCREATE EXTENSION btree_gist;CREATE TABLE schedules ( schedule_id SERIAL NOT NULL PRIMARY KEY, room_number TEXT NOT NULL, -- a range of TIMESTAMP WITH TIME ZONE provides both start and end duration TSTZRANGE, -- table-level constraints imply an index, since otherwise they'd -- have to search the entire table to validate a candidate record; -- GiST (generalized search tree) indexes are usually used in -- Postgres EXCLUDE USING GIST ( room_number WITH =, duration WITH && ));INSERT INTO schedules (room_number, duration)VALUES ('32A', '[2020-08-20T10:00:00Z,2020-08-20T11:00:00Z)');-- the same time in a different room: acceptedINSERT INTO schedules (room_number, duration)VALUES ('32B', '[2020-08-20T10:00:00Z,2020-08-20T11:00:00Z)');-- a half-hour overlap for an already-scheduled room: rejectedINSERT INTO schedules (room_number, duration)VALUES ('32A', '[2020-08-20T10:30:00Z,2020-08-20T11:30:00Z)');
PostgreSQLのON CONFLICT
などのアップサート操作 句またはMySQLのON DUPLICATE KEY UPDATE
テーブルレベルの制約を使用して、競合を検出します。また、null以外の制約と同様に、CHECK
として表すことができます。 制約、一意性制約は、平等の除外制約として表すことができます。
主キー
一意の制約には、特に便利な特殊なケースがあります。 1つまたは複数の一意の列にnull以外の制約を追加すると、テーブル内の各レコードは、制約された列の値によって単独で識別できます。これらの列は、まとめてキーと呼ばれます。 。 users
など、複数の候補キーをテーブルに共存させることができます それでも時々、明確でnull以外のemail
sおよびusername
s;しかし、主キーを宣言することで、レコードが公にそして排他的に知られる単一の基準が確立されます。一部のRDBMSは、この目的のためにクラスター化インデックスと呼ばれる主キーによってページ上の行を編成します。 、主キー値による検索をできるだけ速くするため。
主キーには2つのタイプがあります。自然キーは、テーブルのデータに「自然に」含まれる1つまたは複数の列で定義されますが、代理キーまたは合成キーは、キーになることのみを目的として考案されています。自然キーには注意が必要です。名前から番号付けスキームまで、データベース設計者がしばしば認めるよりも多くのことが変わる可能性があります。国名と地域名を含むルックアップテーブルでは、それぞれのISO 3166コードを安全な自然主キーとして使用できますが、users
名前や電子メールアドレスなどの可変値に基づく自然キーを持つテーブルは、問題を引き起こします。疑わしい場合は、代理キーを作成してください。
自然キーが複数の列にまたがる場合、複数列のキーの管理にはより多くの労力がかかるため、少なくとも代理キーを常に考慮する必要があります。ただし、自然キーが適している場合は、インデックスの場合と同じように、列の特異性を高めて並べ替える必要があります。国コード then 逆ではなく、地域コード。
代理キーは、これまで単一の整数列、つまりBIGINT
でした。 最終的には数十億が割り当てられます。リレーショナルデータベースは、代理キーに一連の次の整数を自動的に入力できます。これは通常、SERIAL
と呼ばれる機能です。 またはIDENTITY
。
自動インクリメントの数値カウンターには欠点があります。事前に生成されたキーを使用してレコードを追加すると競合が発生する可能性があり、シーケンシャル値がユーザーに公開されると、他の有効なキーが何であるかを簡単に推測できます。ユニバーサル一意識別子(UUID)は、これらの弱点を回避し、サロゲートキーの一般的な選択肢になりましたが、ページ内は単純な数値よりもはるかに大きくなっています。 v1(MACアドレスベース)およびv4(疑似ランダム)UUIDタイプが最も頻繁に使用されます。
データベース上:外部キー
リレーショナルデータベースは、
この非公式の「実体関連図」またはERDは、図書館とそのコレクションおよび利用者のデータベースのスキーマの始まりを示しています。各エッジは、接続するテーブル間の関係を表します。 |グリフは横に1つのレコードを示し、「カラスの足」のグリフは複数を表します。図書館には多くの本があり、多くの常連客がいます。
外部キーは、別のテーブルの主キーである列の列(代理キーを優先するポイント:コピーして参照する列は1つだけ)のコピーであり、このテーブルのレコードをその中の「親」レコードにリンクする値があります。上記のスキーマでは、books
テーブルはlibrary_id
を維持します libraries
への外部キー 、本を保持し、author_id
authors
へ 、それらを書く人。しかし、本がauthor_id
で挿入された場合はどうなりますか authors
には存在しません ?
外部キーが制約されていない場合(つまり、それが単なる別の列である場合)、本には存在しない著者が含まれている可能性があります。これは問題です。誰かがbooks
間のリンクをたどろうとした場合 およびauthors
、彼らはどこにも行き着きません。 authors.author_id
の場合 はシリアル整数であるため、偽のauthor_id
まで誰も気付かない可能性もあります。 最終的に割り当てられ、 Don Quixoteの特定のコピーが作成されます。 最初は誰も知らなかったため、次にピエール・メナードが原因で、ミゲル・セルバンテスはどこにも見つかりませんでした。
外部キーを制限しても、誤ったauthor_id
が発生した場合に書籍の属性が誤って表示されるのを防ぐことはできません。 authors
の既存のレコードを指す 、したがって、他のチェックとテストは引き続き重要です。ただし、現存する外部キー値のセットは、ほとんどの場合、可能なの小さなサブセットです。 外部キー値。外部キー制約は、ほとんどの間違った値をキャッチして防止します。外部キー制約がある場合、 Quixote 著者が存在しない場合は、記録される代わりに拒否されます。
これは、「リレーショナルデータベース」の「リレーショナル」の由来ですか?
外部キーはテーブル間の関係を作成しますが、私たちが知っているテーブルは数学的に関係 各属性の可能な値のセットの中で。単一のタプルは、列Aの値を列B以降の値に関連付けます。 E.F.コッドの元の論文は、この意味で「リレーショナル」を使用しています。
これは混乱の終わりを引き起こしておらず、永続的にそうし続ける可能性があります。
特定の正しい値の場合
ここで説明するよりも、データが正しくない可能性のある方法は他にもたくさんあります。制約は役に立ちますが、それでも非常に柔軟です。値が列に表示される回数の制限など、多くの一般的なテーブル内仕様は、トリガーでのみ適用できます。
ただし、テーブルの構造そのものが不整合につながる可能性がある方法もあります。これらを防ぐには、定義と検証だけでなく、正規化するために主キーと外部キーの両方をマーシャリングする必要があります。 テーブル間の関係。ただし、最初に、テーブル間の関係がデータベース自体の構造を定義する方法の表面をかろうじてかじっただけです。