CREATE DOMAIN — 新しいドメインを定義する
CREATE DOMAINname
[ AS ]data_type
[ COLLATEcollation
] [ DEFAULTexpression
] [constraint
[ ... ] ] ここでconstraint
は、以下の通りです。 [ CONSTRAINTconstraint_name
] { NOT NULL | NULL | CHECK (expression
) }
CREATE DOMAIN
は新しいドメインを作成します。
ドメインとは本質的には、特別な制約(使用可能な値集合に対する制限)を持ったデータ型です。
ドメインを定義したユーザが、その所有者となります。
スキーマ名が付けられている場合(例えば、CREATE DOMAIN myschema.mydomain ...
)、ドメインは指定されたスキーマに作成されます。
スキーマ名が付けられていなければ、そのドメインは現在のスキーマに作成されます。
ドメイン名は、そのスキーマ内に存在するデータ型およびドメインの間で、一意である必要があります。
ドメインを使用すると、共通な制約を1箇所に抽象化でき、メンテナンスに便利です。 たとえば、E-mailアドレスを格納する列が複数のテーブルで使用されていて、アドレス構文の検証のためすべてが同一のCHECK制約を必要としているような場合です。 このような場合、各テーブルに個別に制約を設定するよりも、ドメインを定義してください。
ドメインを作成するためには、基となる型に対するUSAGE
を持たなければなりません。
name
作成するドメインの名前です(スキーマ修飾名でも可)。
data_type
ドメインの基となるデータ型です。 配列指定子を含めることができます。
collation
ドメインの照合順(省略可能)です。
照合順序の指定がなければ、ドメインは基となるデータ型と同じ照合順序が使用されます。
COLLATE
が指定される場合、基となる型は照合順序が設定可能な型でなければなりません。
DEFAULT expression
DEFAULT
句は、ドメインデータ型の列のデフォルト値を指定します。
任意の無変数式を値とすることができます(ただし、副問い合わせは許可されません)。
デフォルト式のデータ型は、そのドメインのデータ型と一致する必要があります。
デフォルト値が指定されない場合、デフォルト値はNULL値となります。
デフォルト式は、挿入操作において該当する列に値が指定されなかった場合に使用されます。 特定の列に対してデフォルト値が定義されている場合、それはドメインに関連するデフォルト値より優先します。 反対に、基となるデータ型に関連するデフォルト値より、ドメインのデフォルト値が優先します。
CONSTRAINT constraint_name
制約の名前(省略可能)です。 指定されなければ、システムが名前を生成します。
NOT NULL
このドメインの値としてNULLの使用を禁止します(ただし、以下の注釈を参照してください)。
NULL
ドメインの値としてNULLの使用を許可します。 こちらがデフォルトです。
この句は非標準的なSQLデータベースとの互換性を持つためだけに用意されています。 新しいアプリケーションでこの句を使用するのはお勧めできません。
CHECK (expression
)
CHECK
句は、ドメインの値が満たさなければならない整合性制約や検査を指定します。
各制約は、Boolean型の結果を生成する式である必要があります。
検査される値を参照するには、VALUE
というキーワードを使用すべきです。
TRUEまたはUNKNOWNとして評価される式は成功します。
式の結果がFALSEになった場合、エラーが報告され、値はドメイン型に変換することができません。
現時点では、CHECK
式に副問い合わせを含めたり、VALUE
以外の変数を参照したりすることはできません。
ドメインに複数のCHECK
制約がある場合、それらは名前のアルファベット順に評価されます。
(PostgreSQLの9.5より前のバージョンでは、複数のCHECK
制約がある場合について、特定の実行順序がありませんでした。)
ドメイン制約、特にNOT NULL
は、値がドメイン型に変換されるときに検査されます。
名目上はドメイン型である列が、NOT NULLの制約にも関わらずNULLとして読み出される場合もあり得ます。
例えば、外部結合の問い合わせにおいて、ドメインの列が外部結合のNULLになる側にあるときに、これが起こり得ます。
より微妙な例は以下です。
INSERT INTO tab (domcol) VALUES ((SELECT domcol FROM tab WHERE false));
空でスカラーの副SELECTにより、ドメイン型であると見なされるNULL値が生成されます。 そのため、制約についてこれ以上の検証は行われず、挿入は成功します。
SQLではNULL値はすべてのデータ型で有効な値であると想定されているため、このような問題を回避するのは非常に難しいことです。
したがって、最善の方法は、NOT NULL
制約をドメイン型に直接適用するのではなく、NULL値が許されるようにドメインの制約を設計し、その上で、列のNOT NULL
制約を、必要に応じて、ドメイン型の列に適用することです。
PostgreSQLはCHECK
制約の条件はimmutableである、すなわち同じ入力値に対しては必ず同じ結果を与えると仮定します。
この仮定は、値が初めてドメイン型に変換された時にのみCHECK
制約を確認し、それ以外では確認しないことを正当化するものです。
(これは、5.4.1で述べているテーブルのCHECK
制約の扱いと本質的に同じです。)
この仮定を破るよくある例は、CHECK
式内でユーザ定義関数を参照しており、後でその関数の振舞いを変更することです。
PostgreSQLはそれを拒否しませんが、そのドメイン型の格納された値でCHECK
制約に今や違反するものがあることには気付かないでしょう。
これは、その後のデータベースのダンプとリストアが失敗する原因になるかもしれません。
そのような変更を扱うお勧めの方法は、(ALTER DOMAIN
を使って)制約を削除し、関数の定義を調整し、その制約を再び追加することです。それにより格納されたデータに対して再確認が行われます。
ドメインCHECK
式がエラーを発生しないのを確実にすることもお勧めです。
この例では、データ型us_postal_code
を作成し、その型をテーブル定義の中で使用します。
データが有効なUS郵便番号であるかどうかを検証するために正規表現検査が使用されます。
CREATE DOMAIN us_postal_code AS TEXT CHECK( VALUE ~ '^\d{5}$' OR VALUE ~ '^\d{5}-\d{4}$' ); CREATE TABLE us_snail_addy ( address_id SERIAL PRIMARY KEY, street1 TEXT NOT NULL, street2 TEXT, street3 TEXT, city TEXT NOT NULL, postal us_postal_code NOT NULL );
CREATE DOMAIN
コマンドは標準SQLに準拠しています。