CREATE TABLE(7) SQL Commands CREATE TABLE(7)

CREATE TABLE - 定義一個新表

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 ] } [, ... ] ) [ INHERITS ( parent_table [, ... ] ) ] [ WITH OIDS | WITHOUT OIDS ] [ ON COMMIT { PRESERVE ROWS | DELETE ROWS | DROP } ] where column_constraint is: [ CONSTRAINT constraint_name ] { NOT NULL | NULL | UNIQUE | PRIMARY KEY |
CHECK (expression) |
REFERENCES reftable [ ( refcolumn ) ] [ MATCH FULL | MATCH PARTIAL | MATCH SIMPLE ]
[ ON DELETE action ] [ ON UPDATE action ] } [ DEFERRABLE | NOT DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ] and table_constraint is: [ CONSTRAINT constraint_name ] { UNIQUE ( column_name [, ... ] ) |
PRIMARY KEY ( column_name [, ... ] ) |
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 ]

CREATE TABLE 將在當前資料庫建立一個新的, 初始為空的表。該表將由發出此命令的使用者所有。


如果給出了模式名(比如,CREATE TABLE myschema.mytable ...), 那麼表是在指定模式中建立的。否則它在當前模式中建立。臨時表存在於一個特殊的模式裡, 因此建立臨時表的時候不能給出模式名。表名字必需和同一模式中其他表,序列,索引或者檢視相區別。

CREATE TABLE 還自動建立一個數據型別, 該資料型別代表對應該表一行的複合型別。 因此,表不能和同模式中的現有資料型別同名。


一個表的欄位數不能超過 1600。(實際上,真正的限制比這低,因為還有元組長度的約束)。


可選的約束子句宣告約束(或者測試),新行或者更新的行必須滿足這些約束才能成功插入或更新。 約束是一個它是一個 SQL 物件,它以多種方式協助我們協助我們在表上定義有效的數值集合。


定義約束又兩種方法:表約束和列約束。一個列約束是作為一個列定義的一部分定義的。 而表約束並不和某個列綁在一起, 它可以作用於多於一個列上。每個列約束也可以寫成表約束; 如果某個約束隻影響一個列,那麼列約束只是符號上的簡潔方式而已。


如果聲明瞭此引數,則該表建立為臨時表。臨時表在會話結束時自動刪除, 或者是(可選)在當前事務的結尾(參閱下面的 ON COMMIT)。 現有同名永久表在臨時表存在期間在本會話過程中是不可見的, 除非它們是用模式修飾的名字引用的。 任何在臨時表上建立的索引也都會自動刪除。


我們可以選擇在 TEMPORARY 或 TEMP 前面放上 GLOBAL 或者 LOCAL。 這樣對 PostgreSQL 沒有任何區別,可以參閱 Compatibility [create_table(7)]。


要建立的表的名字(可以用模式修飾)。

在新表中要建立的欄位名字。

該欄位的資料型別。它可以包括陣列說明符。
DEFAULT 子句給它所出現的欄位一個預設數值。 該數值可以是任何不含變數的表示式(不允許使用子查詢和對本表中的其它欄位的交叉引用)。 預設表示式的資料型別必須和欄位型別匹配。


預設表示式將被用於任何未宣告該欄位數值的插入操作。 如果欄位上沒有預設值,那麼預設是 NULL。


和 INHERITS 不同,新表與繼承過來的表之間在建立動作完畢之後是完全無關的。 插入新表的資料不會在父表中表現出來。


欄位預設表示式只有在聲明瞭 INCLUDING DEFAULTS 之後才會繼承過來。 預設是排除預設表示式。


可選的 INHERITS 子句宣告一列表,這個新表自動從這列表中繼承所有欄位。 如果在多於一個父表中存在同名的欄位,那麼就會報告一個錯誤,除非這些欄位的資料型別在每個父表裡都是匹配的。 如果沒有衝突,那麼重複的欄位在新表中融合成一個欄位。 如果新表的欄位名列表中包括和繼承的欄位同名的,那麼它的資料型別也必須和上面一樣與繼承欄位匹配,並且這些欄位定義會融合成一個。 不過,同名的繼承和新欄位宣告可以宣告不同的約束:所有的繼承過來的約束以及宣告的約束都融合到一起,並且全部應用於新表。 如果新表為該欄位明確的聲明瞭一個預設數值,那麼此預設數值覆蓋任何來自繼承欄位宣告的預設值。 否則,任何為該欄位聲明瞭預設數值的父表都必須宣告相同的預設,否則就會報告一個錯誤。

這個可選的子句宣告新表中的行是否應該擁有賦予它們的 OID (物件標識)。 預設是有 OID。(如果新表從任何有 OID 的表繼承而來,那麼就算這條命令說了 WITHOUT OIDS, 也會強制 WITH OIDS。)


宣告 WITHOUT OIDS 允許使用者禁止為行或者表生成 OID。 這麼做對大表是值得的,因為這樣可以減少 OID 消耗並且推遲 32 位 OID 計數器的消耗。 一旦該計數器重疊,那麼就不能再假設 OID 的唯一,這樣它的實用性就大打折扣。 宣告 WITHOUT OIDS 還會減少在磁碟上儲存每行的空間,每行減少 4 位元組,因此也可以改進效能。


列或表約束的可選名字。如果沒有宣告,則由系統生成一個名字。

欄位不允許包含 NULL 數值。

該欄位允許包含 NULL 數值。這是預設。


這個子句的存在只是為和那些非標準 SQL 資料庫相容。 我們不建議在新應用中使用它。

UNIQUE 宣告一個規則,表示一個表裡的一個或者多個獨立的欄位組合的分組只能包含唯一的數值。 表的唯一約束的行為和列約束的一樣,只不過多了跨多行的能力。


對於唯一約束的用途而言,系統認為 NULL 數值是不相等的。


每個唯一表約束都必須命名一個欄位的集合,該集合必須和其它唯一約束命名欄位集合或者該表定義的主鍵約束不同。 (否則就只是同樣的約束寫了兩次。)


主鍵約束表明表中的一個或者一些欄位只能包含唯一(不重複)非 NULL 的數值。 從技術上講,PRIMARY KEY 只是 UNIQUE 和 NOT NULL 的組合,不過把一套欄位標識為主鍵同時也體現了模式設計的元資料, 因為主鍵意味著其它表可以拿這套欄位用做行的唯一標識。


一個表只能宣告一個主鍵,不管是作為欄位約束還是表約束。


主鍵約束應該定義在同個表上的一個與其它唯一約束所定義的不同的欄位集合上。

CHECK 約束宣告一個生成布林結果的子句, 一次插入或者更新操作若想成功則裡面的新行或者被更新的行必須滿足這個條件。 宣告為欄位約束的檢查約束應該只引用該欄位的數值,而在表約束裡出現的表示式可以引用多個欄位。


目前,CHECK 表示式不能包含子查詢也不能引用除當前行欄位之外的變數。


這些子句宣告一個外來鍵約束,外來鍵約束宣告一個由新表中一列或者多列組成的組應該只包含匹配引用的表 reftable 中對應引用的欄位 refcolumn 中的數值。 如果省略 refcolumn, 則使用 reftable 的主鍵。 被引用欄位必須是被引用表中的唯一欄位或者主鍵。


向這些欄位插入的數值將使用給出的匹配型別與參考表中的參考列中的數值進行匹配。 有三種匹配型別:MATCH FULL, MATCH PARTIAL,和 MATCH SIMPLE,它也是預設匹配型別。 MATCH FULL 將不允許一個多欄位外來鍵的欄位為 NULL,除非所有外來鍵欄位都為 NULL。 MATCH SIMPLE 允許某些外來鍵欄位為 NULL 而外來鍵的其它部分不是 NULL。MATCH PARTIAL 還沒實現。


另外,當被參考欄位中的資料改變的時候,那麼將對本表的欄位中的資料執行某種操作。 ON DELETE 子句聲明當被參考表中的被參考行將被刪除的時候要執行的操作。 類似,ON UPDATE 子句宣告被參考表中被參考欄位更新為新值的時候要執行的動作。 如果該行被更新,但被參考的欄位實際上沒有變化,那麼就不會有任何動作。 下面是每個子句的可能的動作:


生成一個錯誤,表明刪除或者更新將產生一個違反外來鍵約束的動作。 它是預設動作。

和 NO ACTION 一樣,只是動作不可推遲, 即使約束剩下的部分是可以推遲的也馬上發生。

刪除任何引用了被刪除行的行,或者分別把引用行的欄位值更新為被參考欄位的新數值。

把引用行數值設定為 NULL。

把引用列的數值設定為它們的預設值。


如果主鍵欄位經常更新,那麼我們給 REFERENCES 欄位增加一個索引可能是合適的,這樣與 REFERENCES 欄位相關聯的 NO ACTION 和 CASCADE 動作可以更有效地執行。


這兩個關鍵字設定該約束是否可推遲。一個不可推遲的約束將在每條命令之後馬上檢查。 可以推遲的約束檢查可以推遲到事務結尾(使用 SET CONSTRAINTS [set_constraints(7)] 命令)。 預設是 NOT DEFERRABLE。目前只有外來鍵約束接受這個子句。所有其它約束型別都是不可推遲的。

如果約束是可推遲的,那麼這個子句宣告檢查約束的預設時間。 如果約束是 INITIALLY IMMEDIATE, 那麼每條語句之後就檢查它。這個是預設。如果約束是 INITIALLY DEFERRED,那麼只有在事務結尾才檢查它。 約束檢查的時間可以用 SET CONSTRAINTS [set_constraints(7)] 命令修改。

我們可以用 ON COMMIT 控制臨時表在事務塊結尾的行為。這三個選項是:

在事務結尾不發生任何特定的動作。這是預設行為。

臨時表的所有行在每次事務結尾都被刪除。實際上,在每次提交的時候都自動 truncate(7)

在當前事務塊的結尾,臨時表將被刪除。


如果一個應用使用了 OID 標識表中的特定行,那麼我們建議在該表的 oid 欄位上建立一個唯一約束,以確保該表的 OID 即使在計數器重疊之後也是唯一的。如果你需要一個整個資料庫範圍的唯一標識, 那麼就要避免假設 OID 是跨表唯一的,你可以用 tableoid 和行 OID 的組合來實現這個目的。 (將來的 PostgreSQL 很可能為每個表使用獨立的 OID 計數器, 因此包括 tableoid 組成資料庫範圍內的唯一標識將是必須的,而不是可選的。)
提示: 對那些沒有主鍵的表,我們不建議使用 WITHOUT OIDS, 因為如果既沒有 OID 又沒有唯一資料鍵字,那麼就很難標識特定的行。
PostgreSQL 自動為每個唯一約束和主鍵約束建立一個索引以確保唯一性。 因此,我們不必為主鍵欄位建立明確的索引。(參閱 CREATE INDEX [create_index(7)]獲取更多資訊。)

唯一約束和主鍵在目前的實現裡是不能繼承的。 這樣,如果把繼承和唯一約束組合在一起會導致無法運轉。


建立表 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 (

vector int[][] );


為表 films 定義一個唯一表約束。 唯一表約束可以在表的一個或多個欄位上定義:

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 定義一個主鍵約束。 下面兩個例子是等效的,第一個例子使用了表約束語法, 第二個使用了列約束表示法。

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 );


在表 distributors 上定義兩個 NOT NULL 列約束,其中之一明確給出了名字:

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) );

CREATE TABLE 遵循 SQL92 和 SQL99 的一個子集,一些例外情況在下面列出。


儘管 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。 在 SQL 裡不存在 ON COMMIT DROP。


SQL 標準說 CHECK 欄位約束只能引用他們施用的欄位; 只有 CHECK 表約束才能引用多個欄位。PostgreSQL 並不強制這個限制;它把欄位和表約束看作相同的東西。

NULL "約束"(實際上不是約束)是 PostgreSQL 對 SQL 標準的擴充套件, 包括它是為了和其它一些資料庫系統相容(以及為了和 NOT NULL 約束對稱)。因為它是任何欄位的預設,所以它的出現只是噪音而已。


透過 INHERITS 子句的多重繼承是 PostgreSQL 語言的擴充套件。 SQL99(但不包括 SQL92)使用不同的語法和語義定義了單繼承。 SQL99 風格的繼承還沒有在 PostgreSQL 中實現。

PostgreSQL 的 OID 的概念不標準。

PostgreSQL 允許建立沒有欄位的表 (比如,CREATE TABLE foo();)。這是對 SQL 標準的擴充套件, 標準不允許存在零欄位表。零欄位表本身沒什麼用,但是禁止他們會給 ALTER TABLE DROP COLUMN帶來很奇怪的情況,所以,這個時候忽視標準的限制好想很清楚。

ALTER TABLE [alter_table(7)], DROP TABLE [drop_table(l)]

譯者

Postgresql 中文網站 何偉平 <laser@pgsqldb.org>

本頁面中文版由中文 man 手冊頁計劃提供。
中文 man 手冊頁計劃:https://github.com/man-pages-zh/manpages-zh

2003-11-02 SQL - Language Statements