制約データ型は、テーブルに格納するデータの種類を限定するための方法です。多くのアプリケーションでは、型が提供する制約では精密さに欠けます。製品の価格が入る列には、おそらく正数のみを受け入れるようにする必要があります。正数のみを受け入れるという標準のデータ型はありません。他の列や行に関連して列データを制約したい場合もあります。製品の情報が入っているテーブルでは、1つの製品番号についての行が2行以上あってはなりません。このような問題を解決するため、SQLでは列およびテーブルに対する制約を定義することができます。制約によってテーブル内のデータを自由に制御することができます。制約に違反するデータを列に格納しようとすると、エラーとなります。このことは、デフォルト値として定義された値を格納する場合にも適用されます。検査制約は最も一般的な制約の種類です。これを使用して、特定の列の値がブーリアン(真の値)の式を満たすように指定できます。製品価格を必ず正数にするには以下のようにします。0));このように、制約の定義はデフォルト値の定義と同様に、データ型の後にきます。デフォルト値と制約は任意の順序で列挙できます。検査制約の構成は、CHECKキーワードの後に続く括弧で囲まれた式です。検査制約式には、制約される列を含む必要があります。しないと、制約はあまり意味のないものになります。制約に個別に名前を付けることもできます。名前を付けることで、エラーメッセージがわかりやすくなりますし、変更したい制約を参照できるようになります。構文は以下の通りです。(この方法で制約名を指定しない場合は、システムにより名前が付けられます)。検査制約では複数の列を参照することもできます。通常価格と割引価格を格納する場合に、必ず割引価格が通常価格よりも低くなるようにしたいとします。discounted_price));最初の2つの制約は上で説明した通りです。3つ目の制約では新しい構文を使っています。これは特定の列に付加されるのではなく、カンマで区切られた列リスト内の別個の項目として現れます。列定義およびこれらの制約定義は、任意の順序で列挙することができます。最初の2つの制約を列制約と言います。これに対し、3つ目の制約は列定義とは別個に書かれるので、テーブル制約と言います。列制約をテーブル制約として書くことはできますが、その逆はできる場合とできない場合があります。列制約は、制約に関連付けられている列のみを参照するためです(PostgreSQLはこの規則を強制しません。他のデータベースシステムと協調して稼動させたい場合はこの規則に従ってください)。上の例は、以下のように書くこともできます。discounted_price));あるいは、次のようにもできます。discounted_price));どのようにするかは好みの問題です。列制約と同様に、テーブル制約に名前を割り当てることができます。discounted_price));検査制約では、検査式が真またはNULL値と評価された場合に、条件が満たされていることになることを説明しなければなりません。ほとんどの式は、どのような演算項目がNULLであってもNULLと評価されるので、制約対象の列ではNULL値を防ぐことはしません。列がNULL値を含まないようにするために、次節で説明する非NULL制約を使用することができます。非NULL制約は単純に、列がNULL値を取らないことを指定します。構文の例は以下の通りです。numeric);非NULL制約は常に列制約として記述されます。NULL)という検査制約と機能的には同等ですが、PostgreSQLでは、明示的に非NULL制約を作成する方がより効果的です。このように作成された非NULL制約に明示的な名前を付けられないのが欠点です。1つの列に複数の制約を適用することもできます。そのためには、次々と制約を書いていくだけです。0));順序は関係ありません。書かれた順序とチェックされる順序は必ずしも同じではありません。NULL制約に対し、逆のパターンであるNULL制約があります。これは、列がNULLでなければならないということではありません。そのような制約は意味がありません。この制約は、列がNULLであってもよいというデフォルトの振舞いを選択するだけのものです。(これは、PostgreSQLと他のデータベースシステムとの互換性のために追加された機能に過ぎません)。スクリプトファイルでの制約の切り替えが簡単であるという理由でこの機能を歓迎するユーザもいます。NULL);と書いてから、必要な場所にNOTキーワードを挿入することができます。NULLとマークする必要があります。よって、列あるいは列のグループに含まれるデータが、テーブル内の全ての行で一意であることを確実にします。列制約の場合の構文は以下の通りです。(product_no));となります。一意性制約が列のグループを参照する場合、各列はカンマで区切って列挙します。c));これは、指定された列の値の組み合わせがテーブル全体で一意であることを指定しています。列の片方が一意である必要はありません(通常一意ではありません)。一意性制約には、以下のようにして名前を割り当てることもできます。numeric);一般に、制約の対象となる列について同じ値を持つ行が、テーブル内に2行以上ある場合は、一意性制約違反になります。この比較では2つのNULL値は等価とはみなされません。一意性制約があったとしても、制約対象の列の少なくとも1つにNULL値を持つ行を複数格納することができるということです。この振舞いは標準SQLに準拠していますが、この規則に従わないSQLデータベースもあるそうです。移植する予定のアプリケーションを開発する際には注意してください。技術的には、プライマリキー制約は単純に一意性制約と非NULL制約を組み合わせたものです。次の2つのテーブル定義は同じデータを受け入れます。numeric);プライマリキーでも複数の列を制約することができ、その構文は一意性制約に似ています。(このことは、プライマリキーの定義からの直接の帰結です。一意性制約ではNULL値を除外しないため、一意の識別子が提供されないことに注意してください)。これは文書化、および、クライアントアプリケーションの両方の面で役に立ちます。行値の変更が可能なGUIアプリケーションが行を一意的に特定するためには、おそらくテーブルのプライマリキーを知る必要があります。(一意性制約および非NULL制約には個数の制限はありません。機能的には同じものですが、プライマリキーとして識別される制約は1つのみです)。リレーショナルデータベース理論では、全てのテーブルにプライマリキーが1つ必要とされています。この規則はPostgreSQLでは強制されませんが、たいていの場合はこれに従うことが推奨されます。外部キー制約は、列(または列のグループ)の値が、他のテーブルの行の値と一致しなければならないことを指定します。これによって関連する2つのテーブルの参照整合性が維持されます。これでまで何度か例に使用したproductsテーブルについて考えてみます。numeric);また、これらの製品に対する注文を格納するテーブルも作成済みだとしましょう。この注文のordersテーブルには実際に存在する製品の注文のみを格納したいと思っています。そこで、productsテーブルを参照するordersテーブルに外部キー制約を定義します。integer);これで、productsテーブルに存在しないproduct_no項目を使用して注文を作成することはできなくなります。このような場合に、ordersテーブルのことを参照テーブル、productテーブルのことを被参照テーブルと呼びます。同様に、参照列と被参照列もあります。上記のコマンドは、次のように短縮することもできます。integer);列リストがないため、被参照テーブルのプライマリキーが被参照列(複数可)として使用されます。外部キーでも、列のグループを制約したり参照したりすることもできます。これもまた、テーブル制約の形式で記述する必要があります。以下は、説明のための非現実的な例です。c2));もちろん、制約される列数および型は、被参照列の数および型と一致しなければなりません。外部キーには、以下のようにして名前を割り当てることもできます。テーブルには複数の外部キー制約を含めることができます。このことはテーブル間の多対多関係を実装するために使用されます。(上の例の構造では不可能です)。この場合、次のテーブル構造を使用できます。order_id));最後のテーブルで、プライマリキーと外部キーが重なっていることに注目してください。外部キーが製品に関連付けられていない注文の作成を許可しないことは、既に説明した通りです。ある注文で参照していた製品が、注文後に削除されたらどうなるでしょう。SQLではこのような場合も扱うことができます。直感的に、いくつかのオプションが考えられます。参照される製品の削除を許可しない注文も一緒に削除する他にもありますか?具体例として、上の例の多対多関係に次のポリシーを実装してみましょう。(order_itemsによって)注文で参照されたままの製品を除去しようしても、この操作を行えないようにします。注文が除去されると、注文項目も除去されます。order_id));削除の制限およびカスケードという2つは、最も一般的なオプションです。RESTRICTは、被参照行が削除されるのを防ぎます。ACTIONは、制約がチェックされた時に参照行がまだ存在していた場合に、エラーとなることを意味しています。ACTIONではチェックをトランザクション中で後回しにすることができるのに対し、RESTRICTでは後回しにできないということです)。CASCADEは被参照行が削除された時、それを参照する行(複数可)も同様に削除されなければならないことを指定します。他にも2つのオプションがあります。これらは、被参照行が削除された際に、参照列がそれぞれNULLかデフォルトに設定されるようになります。これらは制約を守ることを免除することではない、ということに注意してください。DEFAULTを指定したとしても、デフォルト値が外部キー制約を満たさない場合には操作は失敗します。UPDATEもあります。これらが行えるアクションは同じです。データの更新および削除について詳しくは、第6章を参照してください。最後に、外部キーはプライマリキーまたは一意性制約のいずれかである列を参照している必要があります。外部キーが一意性制約を参照している場合、NULL値をどのようにマッチさせるかに関する他の方法がいくつかあります。TABLEに説明があります。