CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } ] TABLE table_name ( [ { column_name data_type [ DEFAULT default_expr ] [ column_constraint [ ... ] ] | table_constraint | LIKE parent_table [ { INCLUDING | EXCLUDING } { DEFAULTS | CONSTRAINTS } ] ... } [, ... ] ] ) [ INHERITS ( parent_table [, ... ] ) ] [ WITH ( storage_parameter [= value] [, ... ] ) | WITH OIDS | WITHOUT OIDS ] [ ON COMMIT { PRESERVE ROWS | DELETE ROWS | DROP } ] [ TABLESPACE tablespace ] column_constraintには、次の構文が入ります。 [ CONSTRAINT constraint_name ] { NOT NULL | NULL | UNIQUE index_parameters | PRIMARY KEY index_parameters | CHECK ( expression ) | REFERENCES reftable [ ( refcolumn ) ] [ MATCH FULL | MATCH PARTIAL | MATCH SIMPLE ] [ ON DELETE action ] [ ON UPDATE action ] } [ DEFERRABLE | NOT DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ] また、table_constraintには、次の構文が入ります。 [ CONSTRAINT constraint_name ] { UNIQUE ( column_name [, ... ] ) index_parameters | PRIMARY KEY ( column_name [, ... ] ) index_parameters | CHECK ( expression ) | FOREIGN KEY ( column_name [, ... ] ) REFERENCES reftable [ ( refcolumn [, ... ] ) ] [ MATCH FULL | MATCH PARTIAL | MATCH SIMPLE ] [ ON DELETE action ] [ ON UPDATE action ] } [ DEFERRABLE | NOT DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ] UNIQUEおよびPRIMARY KEY制約内のindex_parametersは以下の通りです。 [ WITH ( storage_parameter [= value] [, ... ] ) ] [ USING INDEX TABLESPACE tablespace ]
CREATE TABLEは、現在のデータベースに新しい空のテーブルを作成します。 作成したテーブルはこのコマンドを実行したユーザが所有します。
スキーマ名が付けられている場合(例えば、CREATE TABLE myschema.mytable ...)、テーブルは指定されたスキーマで作成されます。 スキーマ名がなければ、テーブルは現在のスキーマで作成されます。 また、一時テーブルは特別なスキーマに存在するため、一時テーブルの作成時にスキーマ名を与えることはできません。 テーブル名は、同じスキーマ内の他のテーブル、シーケンス、インデックス、ビューとは異なる名前にする必要があります。
さらに、CREATE TABLEは、作成するテーブルの1行に対応する複合型のデータ型を作成します。 したがって、テーブルは、同じスキーマ内の既存のデータ型と同じ名前を持つことができません。
制約句には、挿入、更新操作を行うために、新しい行、または更新する行が満たさなければならない制約(検査項目)を指定します。制約句は省略可能です。 制約は、テーブル内で様々な有効な値の集合を定義する際、役に立つSQLオブジェクトです。
制約の定義にはテーブル制約と列制約という2種類があります。 列制約は列定義の一部として定義されます。 テーブル制約定義は、特定の列とは結びつけられておらず、複数の列を含有することができます。 また、全ての列制約はテーブル制約として記述することができます。 列制約は、1つの列にのみ影響する制約のための、簡便な記述方法に過ぎません。
このパラメータが指定された場合、テーブルは一時テーブルとして作成されます。 一時テーブルは、そのセッションの終わり、場合によっては、現在のトランザクションの終わり(後述のON COMMITを参照)に自動的に削除されます。 一時テーブルが存在する場合、同じ名前を持つ既存の永続テーブルは、スキーマ修飾名で参照されていない限り、現在のセッションでは非可視になります。 一時テーブルで作られるインデックスも、全て自動的に一時的なものとなります。
GLOBALまたはLOCALをTEMPORARYやTEMPの前に記述することができます(省略可能)。 PostgreSQLでは、これらを指定しても動作の違いはありません。 互換性を参照してください。
作成するテーブルの名前です(スキーマ修飾名でも可)。
新しいテーブルで作成される列の名前です。
列のデータ型です。 これには、配列指定子が含まれる場合があります。 PostgreSQLでサポートされるデータ型の情報に関する詳細は第8章を参照してください。
DEFAULT句を列定義に付けると、その列にデフォルトデータ値が割り当てられます。 値として指定するのは、任意の無変数式です(副問い合わせと現在のテーブル内の他の列へ交差参照は許可されません)。 デフォルト式のデータ型はその列のデータ型と一致する必要があります。
デフォルト式は、全ての挿入操作において、その列に値が指定されていない場合に使用されます。 列にデフォルト値がない場合、デフォルト値はNULLになります。
INHERITS句でテーブルの一覧を指定すると、新しいテーブルは指定されたテーブルの全ての列を自動的に継承します。この句は省略可能です。
INHERITSを使用すると、新しい子テーブルとその親テーブル(複数可)との間に永続的な関連が作成されます。 通常、親へのスキーマ修飾子は同様に子にも伝播します。また、デフォルトでは、親テーブルの走査結果には子テーブルのデータが含まれます。
複数の親テーブルに同一名の列が存在する場合、それらのデータ型が一致していなければ、エラーとして報告されます。 競合がなければ、これらの重複した列は新しいテーブルで1つの列の形に融合されます。 新しいテーブルの列名の一覧に継承する列の名前が含まれる場合も、そのデータ型は継承する列のデータ型と一致していなければなりません。さらに、その列定義は1つに融合されます。 しかし、同一名称の新しい列の宣言内で、継承する列と同一の制約を指定する必要はありません。 任意の宣言で提供される制約は、まとめてマージされ、全てが新しいテーブルに適用されます。 新しいテーブルで明示的に列のデフォルト値を指定した場合、継承した列宣言における全てのデフォルト値は上書きされます。 デフォルト値を指定しなかった場合、親側でデフォルト値が指定されている時は、それらのデフォルト値が全て同じ値でなければなりません。 値が違う場合はエラーになります。
LIKE句にテーブルを指定すると、自動的にそのテーブルの全ての列名、そのデータ型、非NULL制約が新しいテーブルにコピーされます。
INHERITSとの違いは、作成した後、新しいテーブルと元のテーブルが完全に分離されることです。 元のテーブルへの変更は新しいテーブルには適用されません。また、元のテーブルを操作しても新しいテーブルのデータは見つかりません。
コピーする列のデフォルト式は、INCLUDING DEFAULTSが指定された場合にのみコピーされます。 デフォルトでは、デフォルト式がコピーされないため、新しいテーブルのコピーされた列はデフォルト値としてNULLを持つことになります。
非NULL制約は常に新しいテーブルにコピーされます。 CHECK制約は、INCLUDING CONSTRAINTSが指定された場合にのみコピーされます。 他の種類の制約は決してコピーされません。 また、列制約とテーブル制約とを区別しません。 制約が要求される場合は、すべての検査制約がコピーされます。
また、INHERITSと異なり、同じ名前の列や制約を持つ場合、コピーされた列と制約はまとめられません。 同じ名前が明示的に、あるいは他のLIKE句で指定された場合、エラーが通知されます。
省略可能な列制約、テーブル制約の名前です。 もし、この制約に違反すると、制約名がエラーメッセージに含まれるようになります。 ですので、col must be positive(正数でなければならない)といった名前の制約名を付与することで、クライアントアプリケーションへ有用な制約情報を渡すことができます。 (空白を含む制約名を指定する場合、二重引用符が必要です。) 指定されなければ、システムが名前を生成します。
その列がNULL値を持てないことを指定します。
その列がNULL値を持てることを指定します。 これがデフォルトです。
この句は非標準的なSQLデータベースとの互換性のためだけに提供されています。 新しいアプリケーションでこれを使用するのはお勧めしません。
UNIQUE制約は、テーブルの1つまたは複数の列からなるグループが、一意な値のみ持つことを指定します。 一意性テーブル制約の動作は一意性列制約と同じですが、さらに複数列にまたがる機能を持ちます。
一意性制約では、NULL値は等しいとはみなされなせん。
それぞれの一意性テーブル制約には、そのテーブルの他の一意性制約もしくはプライマリキー制約によって名付けられた列の集合とは、異なる名前の列の集合を指定しなければなりません (同じ名前を指定すると、同じ制約が2回現れるだけになります)。
プライマリキー制約は、テーブルの1列または複数列が一意な(重複がない)、非NULL値のみを持つことを指定します。 技術的には、PRIMARY KEYは単なるUNIQUEとNOT NULLの組み合わせです。しかし、プライマリキーであることは他のテーブルがその列集合を一意な行識別子とみなせることを意味するので、列集合をプライマリキーと特定すると、スキーマ設計に関するメタデータを提供することになります。
列制約であるかテーブル制約であるかにかかわらず、1つのテーブルに指定できるプライマリキーは1つだけです。
プライマリキー制約には、そのテーブルに定義された他の一意性制約で指名された列の集合とは違う組み合わせの列の集合を指定しなければなりません。
CHECK句は、挿入や更新操作を行うために、新しい行、または変更する行が満たさなければならない、Boolean型の結果を返す式を指定します。 式の評価がTRUEもしくはUNKNOWNとなれば成功です。 行の挿入、更新操作の結果、式がFALSEとなる場合は、エラー例外が生成され、挿入や更新によるデータベースの変更は行われません。 列制約として指定された検査制約は、その列の値のみを参照しなければなりません。 一方、テーブル制約として現れる式は、複数列を参照することができます。
現在、CHECK式には、副問い合わせや現在の行の列以外の値を含むことはできません。
これらの句は、外部キー制約を指定します。 外部キー制約は、新しいテーブルの1つまたは複数の列の集合が、被参照テーブルの一部の行の被参照列(複数可)に一致する値を持たなければならないことを指定するものです。 refcolumnが省略された場合、reftableのプライマリキーが使用されます。 被参照列は、被参照テーブルにおいて一意性制約もしくはプライマリキー制約を持った列でなければなりません。 一時テーブルと永続テーブルとの間で外部キー制約を定義できないことに注意してください。
参照列に挿入された値は、被参照テーブルと被参照列の値に対して、指定した照合型で照会されます。 照合型には3種類があります。 MATCH FULL、MATCH PARTIAL、デフォルトでもあるMATCH SIMPLE照合型です。 MATCH FULLは全ての外部キー列がNULLとなる場合を除き、複数列外部キーのある列がNULLとなることを許可しません。 MATCH SIMPLE照合型は、外部キーの他の部分がNULLでない限り、外部キーの一部をNULLとなることを許可します。 MATCH PARTIALはまだ実装されていません。
さらに、被参照列のデータが変更された場合、このテーブルの列のデータに何らかの動作が発生します。 ON DELETE句は、被参照テーブルの被参照行が削除された場合の動作を指定します。 同様にON UPDATE句は、被参照テーブルの被参照列が新しい値に更新された場合の動作を指定します。 行の更新があった場合でも、被参照列が実際に変更されない場合は、動作は実行されません。 制約が遅延可能と宣言されていても、NO ACTION検査以外の参照動作は遅延させられません。 各句について、以下の動作を指定可能です。
削除もしくは更新が外部キー制約違反となることを示すエラーを発生します。 制約が遅延可能な場合、何らかの参照行が存在する限り、このエラーは制約の検査時点で発生します。 これはデフォルトの動作です。
削除もしくは更新が外部キー制約違反となることを示すエラーを発生します。 検査が遅延できない点を除き、NO ACTIONと同じです。
削除された行を参照している行は全て削除します。また、参照している列の値を、被参照列の新しい値にします。
参照する列(複数可)をNULLに設定します。
参照する列(複数可)をそのデフォルト値に設定します。
被参照列が頻繁に更新される場合、外部キー列にインデックスを付け、その外部キー列に関連する参照動作がより効率的に実行できるようにする方が良いでしょう。
制約を遅延させることが可能かどうかを制御します。 遅延不可の制約は各コマンドの後すぐに検査されます。 遅延可能な制約の検査は、(SET CONSTRAINTSコマンドを使用して)トランザクションの終了時まで遅延させることができます。 NOT DEFERRABLEがデフォルトです。 現在、外部キー制約のみがこの句を受け付けることができます。 他の制約は遅延させることができません。
制約が遅延可能な場合、この句は制約検査を行うデフォルトの時期を指定します。 制約がINITIALLY IMMEDIATEの場合、各文の実行後に検査されます。 これがデフォルトです。 制約がINITIALLY DEFERREDの場合、トランザクションの終了時にのみ検査されます。 制約検査の時期はSET CONSTRAINTSコマンドを使用して変更することができます。
この句は、テーブルまたはインデックスに対して省略可能な格納パラメータを指定します。 詳細は格納パラメータを参照してください。 テーブル用のWITHには、OIDS=TRUE(もしくは単なるOIDS)を含めて、新しいテーブルの行が行に割り当てられたOID(オブジェクト識別子)を持たなければならないことを指定することもできます。 また、OIDS=FALSEを含めて、OIDを持たないことを指定することもできます。 OIDSが指定されない場合、デフォルトの設定はdefault_with_oids設定パラメータに依存します。 (新しいテーブルがOIDを持つテーブルから継承する場合、コマンドでOIDS=FALSEと指定しても強制的にOIDS=TRUE となります。)
OIDS=FALSEが明示的または暗黙的に指定されている場合、新しいテーブルはOIDを格納しません。また、挿入される行にはOIDが割り当てられません。 このような動作は一般的に有益であると考えられます。それは、OIDの使用を抑え、32ビットのOIDカウンタの回転周期を延長できるためです。 カウンタが一周するとOIDの一意性を保証できなくなるので、その有用性を減少させることになります。 また、OIDをなくすことで、テーブル1行当たり(ほとんどのマシンで)4バイト分、テーブルをディスクに格納するための容量を軽減するので、多少性能が向上します。
テーブルの作成後にOIDを削除するには、ALTER TABLEを使用してください。
これは古い構文で、それぞれWITH (OIDS) and WITH (OIDS=FALSE)と同じです。 OIDSの設定と格納パラメータの設定の両方を指定したい場合は、上述のWITH ( ... )を使用しなければなりません。
ON COMMITを使用して、トランザクションブロックの終了時点での一時テーブルの動作を制御することができます。 以下の3つのオプションがあります。
トランザクションの終了時点で、特別な動作は行われません。 これがデフォルトの動作です。
一時テーブル内の全ての行は、各トランザクションブロックの終わりで削除されます。 基本的には、コミットの度に自動的にTRUNCATE>が実行されます。
一時テーブルは、現在のトランザクションブロックの終了時点で削除されます。
tablespaceは、新しいテーブルが作成されるテーブル空間名です。 指定されていない場合、default_tablespaceが使用されます。 default_tablespaceが空文字列であれば、データベースのデフォルトのテーブル空間が使用されます。
この句により、UNIQUEまたはPRIMARY KEY制約に関連したインデックスを作成するテーブル空間を選択することができます。 指定されていない場合、default_tablespaceが使用されます。 default_tablespaceが空文字列であれば、データベースのデフォルトのテーブル空間が使用されます。
WITH句により、テーブルおよびUNIQUEまたはPRIMARY KEY制約と関連づいたインデックスの格納パラメータを指定することができます。 インデックスの格納パラメータについてはCREATE INDEXで説明します。 現在、テーブルでは以下の格納パラメータのみが設定可能です。
テーブルのfillfactorは10から100までの間の割合(パーセント)です。 100(完全にすべて使用)がデフォルトです。 より小さな値を指定すると、INSERT操作は指定した割合までしかテーブルページを使用しません。 各ページの残りの部分は、そのページ内の行更新用に予約されます。 これによりUPDATEは、元の行と同じページ上に更新済みの行の複製を格納することができるようになります。 これは別のページに更新済みの行の複製を格納することよりも効率的です。 項目の更新がまったくないテーブルでは、完全にすべてを使用することが最善の選択です。 しかし、更新が非常に多いテーブルではより小さめのfillfactorが適切です。
新規のアプリケーションでOIDを使用するのはお勧めしません。 できる限り、テーブルのプライマリキーとしてSERIALや他のシーケンスジェネレータを使用する方が望ましいと考えられます。 しかし、アプリケーションがテーブルの特定の行を識別するためにOIDを使用する場合は、そのテーブルのoid列に一意性制約を作成することを推奨します。 これにより、カウンタが一周してしまった場合でも、テーブル内のOIDで一意に行を識別できることが保証されるからです。 OIDがテーブル全体で一意であると考えるのは止めてください。 データベース全体で一意な識別子が必要な場合は、tableoidと行のOIDの組み合わせを使用してください。
ティップ: OIDS=FALSEの使用は、プライマリキーのないテーブルでは推奨されません。 OIDも一意なデータキーも存在しないと、特定行を識別することが難しくなるからです。
PostgreSQLは自動的に各一意性制約とプライマリキー制約に対してインデックスを作成し、その一意性を確実なものにします。 したがって、プライマリキーの列に明示的なインデックスを作成することは必要ありません (詳細についてはCREATE INDEXを参照してください)。
現在の実装では、一意性制約とプライマリキーは継承されません。 これは、継承と一意性制約を組み合わせると障害が発生するからです。
テーブルは1600列以上の列を持つことはできません (タプル長の制限により実際の制限はもっと低くなります)。
filmsテーブルとdistributorsテーブルを作成します。
CREATE TABLE films ( code char(5) CONSTRAINT firstkey PRIMARY KEY, title varchar(40) NOT NULL, did integer NOT NULL, date_prod date, kind varchar(10), len interval hour to minute );
CREATE TABLE distributors ( did integer PRIMARY KEY DEFAULT nextval('serial'), name varchar(40) NOT NULL CHECK (name <> '') );
2次元配列を持つテーブルを作成します。
CREATE TABLE array_int ( vector int[][] );
filmsテーブルに 一意性テーブル制約を定義します。 一意性テーブル制約はテーブルの1つ以上の列に定義することができます。
CREATE TABLE films ( code char(5), title varchar(40), did integer, date_prod date, kind varchar(10), len interval hour to minute, CONSTRAINT production UNIQUE(date_prod) );
検査列制約を定義します。
CREATE TABLE distributors ( did integer CHECK (did > 100), name varchar(40) );
検査テーブル制約を定義します。
CREATE TABLE distributors ( did integer, name varchar(40) CONSTRAINT con1 CHECK (did > 100 AND name <> '') );
filmsテーブルにプライマリキーテーブル制約を定義します。
CREATE TABLE films ( code char(5), title varchar(40), did integer, date_prod date, kind varchar(10), len interval hour to minute, CONSTRAINT code_title PRIMARY KEY(code,title) );
distributorsテーブルにプライマリキー制約を定義します。 以下の2つの例は同じものです。 前者はテーブル制約構文を使用し、後者は列制約構文を使用します。
CREATE TABLE distributors ( did integer, name varchar(40), PRIMARY KEY(did) );
CREATE TABLE distributors ( did integer PRIMARY KEY, name varchar(40) );
以下では、name列のデフォルト値にリテラル定数を割り当てています。また、did列のデフォルト値として、シーケンスオブジェクトの次の値が生成されるように調整しています。 modtimeのデフォルト値は、その行が挿入された時刻となります。
CREATE TABLE distributors ( name varchar(40) DEFAULT 'Luso Films', did integer DEFAULT nextval('distributors_serial'), modtime timestamp DEFAULT current_timestamp );
2つのNOT NULL列制約をdistributors
テーブルに定義します。
そのうち1つには明示的な名前を付けています。
CREATE TABLE distributors ( did integer CONSTRAINT no_null NOT NULL, name varchar(40) NOT NULL );
name列に対し、一意性制約を定義します。
CREATE TABLE distributors ( did integer, name varchar(40) UNIQUE );
上をテーブル制約として指定します。
CREATE TABLE distributors ( did integer, name varchar(40), UNIQUE(name) );
テーブルとその一意性インデックスに70%のfillファクタを指定して、同じテーブルを作成します。
CREATE TABLE distributors ( did integer, name varchar(40), UNIQUE(name) WITH (fillfactor=70) ) WITH (fillfactor=70);
diskvol1テーブル空間にcinemasテーブルを作成します。
CREATE TABLE cinemas ( id serial, name text, location text ) TABLESPACE diskvol1;
CREATE TABLEは、以下の一覧を除いて、標準SQLに従います。
CREATE TEMPORARY TABLEは標準SQLに類似していますが、その効果は同じではありません。 標準では、一時テーブルは一度だけ定義され、それを必要とするセッションごとに自動的に(空の内容で始まる形で)出現します。 PostgreSQLでは、これと異なり、各セッションで独自に、使用する一時テーブル用のCREATE TEMPORARY TABLEコマンドを発行しなければなりません。 これにより、異なるセッションで同じ名前の一時テーブルを異なる目的で使用することができます。 一方、標準の方法では、ある一時テーブル名を持つインスタンスが、全て同一のテーブル構造を持つという制限があります。
標準におけるこのような一時テーブルの動作定義はたいてい無視されています。 この点でのPostgreSQLの動作は、他の多くのSQLデータベースと似ています。
標準における、グローバル一時テーブルとローカル一時テーブルの区別はPostgreSQLにはありません。 この区別はモジュールという概念に依存したものですが、PostgreSQLにはモジュール概念がないからです。 互換性を保持するため、PostgreSQLは一時テーブルの宣言においてGLOBALとLOCALキーワードを受け付けますが、これらには何の効果もありません。
一時テーブル用のON COMMIT句もまた、標準SQLに類似していますが、数点の違いがあります。 ON COMMIT句が省略された場合、SQLでは、デフォルトの動作はON COMMIT DELETE ROWSであると規定しています。 しかし、PostgreSQLでのデフォルトの動作はON COMMIT PRESERVE ROWSです。 また、ON COMMIT DROPはSQLにはありません。
標準SQLでは、CHECK列制約はそれを適用する列のみを参照でき、複数の列を参照できるのはCHECKテーブル制約のみであるとされています。 PostgreSQLにはこの制限はありません。 列検査制約とテーブル検査制約を同様のものとして扱っています。
NULL"制約"(実際には非制約)は、標準SQLに対するPostgreSQLの拡張で、他のいくつかのデータベースシステムとの互換性のために含まれています(NOT NULL制約と対称になります)。 どんな列に対してもデフォルトとなるため、これはノイズに過ぎません。
INHERITS句による複数継承は、PostgreSQLの言語拡張です。 SQL:1999以降では、異なる構文と意味体系による単一継承を定義しています。 今のところ、SQL:1999方式の継承はPostgreSQLではサポートされていません。