全部產品
Search
文件中心

PolarDB:ALTER TABLE

更新時間:Jul 06, 2024

ALTER TABLE用於更改一個現有表的定義。

簡介

ALTER TABLE更改一個現有表的定義。下文描述了幾種形式。注意每一種形式所要求的鎖層級可能不同。如果沒有明確說明,將會獲得一個ACCESS EXCLUSIVE鎖。當給出多個子命令時,獲得的鎖將是子命令所要求的最嚴格的那一個。

ADD COLUMN [ IF NOT EXISTS ]這種形式向該表增加一個新列,使用與 CREATE TABLE 相同的文法。如果指定了 IF NOT EXISTS並且使用這個名字的列已經存在,則不會拋出錯誤。

DROP COLUMN [ IF EXISTS ]這種形式從表刪除一列。涉及到該列的索引和資料表條件約束也將會被自動刪除。如果該列的移除會導致引用它的多元統計資訊僅包含單一列的資料,則該多元統計資訊也將被移除。如果在該表之外有任何東西(例如外鍵引用或者視圖)依賴於該列,你將需要用到CASCADE。如果指定了 IF EXISTS但該列不存在,則不會拋出錯誤。 這種情況中會發出一個提示。

SET DATA TYPE這種形式更改表中一列的類型。涉及到該列的索引和簡單資料表條件約束將通過重新解析最初提供的運算式被自動轉換為使用新的列類型。可選的 COLLATE子句為新列指定一種定序,如果被省略, 定序會是新列類型的預設定序。可選的USING 子句指定如何從舊的列值計算新列值,如果被省略,預設的轉換和從舊類型到新類型的賦值造型一樣。如果沒有從舊類型到新類型的隱式或者賦值造型, 則必須提供一個USING子句。

SET/DROP DEFAULT這些表單設定或刪除列的預設值(其中刪除等同於將預設值設定為 NULL)。 新的預設值僅適用於後續的INSERTUPDATE命令; 它不會導致表中已有的行發生更改。

SET/DROP NOT NULL這些形式更改一列是否被標記為允許空值或者拒絕空值。

SET NOT NULL 只能應用於列,前提是表中沒有任何記錄包含該列的NULL值。 通常,這一點在ALTER TABLE全表掃描時來檢查;但是,如果找到有效CHECK約束證明不存在NULL,則跳過表掃描。

如果這個表是一個分區,對於在父表中被標記為NOT NULL的列,不能在其上執行DROP NOT NULL。要從所有的分區中刪除NOT NULL約束,可以在父表上執行DROP NOT NULL。即使在父表上沒有NOT NULL約束,這樣的約束還是能被增加到分區上。也就是說,即便父表允許空值,子表也可以不允許空值,但反過來不行。

DROP EXPRESSION [ IF EXISTS ]此表單將儲存的產生的列轉換為普通的基本欄。列中的現有資料將會保留, 但未來的更改將不會應用於產生的運算式。

如果指定了DROP EXPRESSION IF EXISTS,並且該列不是儲存的已產生列,不會拋出任何錯誤。 在這種情況下,將發出通知。

ADD GENERATED { ALWAYS | BY DEFAULT } AS IDENTITYSET GENERATED { ALWAYS | BY DEFAULT }DROP IDENTITY [ IF EXISTS ]這些形式更改一列是否是一個識別欄位,或者是更改一個已有的識別欄位的產生屬性。詳情請參考 CREATE TABLE 。 像SET DEFAULT一樣,這些形式僅影響隨後的INSERTUPDATE命令的行為。 它們不會導致表中已有的行發生更改。

如果DROP IDENTITY IF EXISTS被指定並且該列不是一個識別欄位,則不會有錯誤被拋出。在這種情況下會發出一個提示。

SET sequence_optionRESTART這些形式修改位於一個現有識別欄位之下的序列。 sequence_option是一個 ALTER SEQUENCE 所支援的選項,例如INCREMENT BY

SET STATISTICS這種形式為後續的 ANALYZE 操作設定針對每列的統計收集目標。目標可以被設定在範圍 0 到 10000 之間,還可以把它設定為 -1 來恢複到使用系統預設的統計目標(default_statistics_target)。

SET STATISTICS要求一個SHARE UPDATE EXCLUSIVE鎖。

SET ( attribute_option = value [, ... ] )RESET ( attribute_option [, ... ] )這種形式設定或者重設每個屬性的選項。當前,已定義的針對每個屬性的選項只有n_distinctn_distinct_inherited, 它們會覆蓋後續 ANALYZE 操作所得到的可區分值數量估計。n_distinct影響該表本身的統計資訊,而 n_distinct_inherited影響為該表外加其繼承子女收集的統計資訊。 當被設定為一個正值時,ANALYZE將假定該列剛好包含指定數量的可區分非空值。當被設定為一個負值(必須大於等於 -1)時, ANALYZE將假定可區分非空值的數量與表的尺寸成線性比例, 確切的計數由估計的表尺寸乘以給定數位絕對值計算得到。例如,值 -1 表示該列中所有的值都是可區分的,而值 -0.5 則表示每一個值平均出現兩次。當表的尺寸隨時間變化時,這會有所協助,因為這種計算只有在查詢規劃時才會被執行。指定值為 0 將回到正常的估計可區分值數量的做法。

更改針對每個屬性的選項要求一個 SHARE UPDATE EXCLUSIVE鎖。

SET STORAGE 這種形式為一列設定儲存模式。這會控制這列是會被保持線上內還是放在一個二級 TOAST 表中,以及資料是否應被壓縮。對於 integer之類的定長、線內、未壓縮值必須使用 PLAINMAIN用於線內、可壓縮的資料。EXTERNAL用於外部的、未壓縮資料。而 EXTENDED用於外部的、壓縮資料。對於大部分支援非-PLAIN儲存的資料類型,EXTENDED 是預設值。使用EXTERNAL將會讓很大的 textbytea之上的子串操作運行得更快, 但是代價是儲存空間會增加。注意SET STORAGE本身並不改變表中的任何東西,它只是設定在未來的表更新時要追求的策略。

ADD table_constraint [ NOT VALID ]這種形式使用和 CREATE TABLE 相同的約束文法外加 NOT VALID選項為一個表增加一個新的約束,該選項當前只被允許用於外鍵和 CHECK 條件約束。

通常,此表單將導致對錶進行掃描,以驗證表中的所有現有行是否滿足新約束。 但是如果使用了 NOT VALID選項 ,則跳過此可能很漫長的掃描。 該約束仍將被強制到後續的插入和刪除上(也就是說,在外鍵的情況下如果在被參考資料表中沒有一個匹配的行,操作會失敗;或者如果新行不匹配指定的檢查條件,操作也會失敗)。 但是資料庫不會假定約束對該表中的所有行都成立,直到通過使用VALIDATE CONSTRAINT選項對它進行驗證。

儘管大多數形式的ADD table_constraint 都需要ACCESS EXCLUSIVE鎖,但ADD FOREIGN KEY僅需要SHARE ROW EXCLUSIVE鎖。 請注意,除了聲明約束的表上的鎖之外,ADD FOREIGN KEY還獲得了對參考資料表的SHARE ROW EXCLUSIVE鎖。

當唯一或者主鍵約束被添加到分區表時,會有額外的限制,請參考 CREATE TABLE。 此外,當前分區表上的外鍵約束不能被聲明為NOT VALID

ADD table_constraint_using_index這種形式基於一個已有的唯一索引為一個表增加新的 PRIMARY KEYUNIQUE約束。該索引中的所有列將被包括在約束中。

該索引不能有運算式列或者是一個部分索引。還有,它必須是一個帶有預設排序次序的 B-樹索引。這些限制確保該索引等效於使用常規 ADD PRIMARY KEY或者ADD UNIQUE命令時建立的索引。

如果PRIMARY KEY被指定,並且該索引的列沒有被標記 NOT NULL,那麼這個命令將嘗試對每一個這樣的列做 ALTER COLUMN SET NOT NULL。這需要一次全表掃描來驗證這些列不包含空值。在所有其他情況中,這都是一種很快的操作。

如果提供了一個約束名,那麼該索引將被重新命名以匹配該約束名。否則該約束將被命名成索引的名稱。

這個命令被執行後,該索引被增加的約束“擁有”,這和用常規 ADD PRIMARY KEYADD UNIQUE命令建立的索引一樣。特別地,刪掉該約束將會導致該索引也消失。

當前在分區表上不支援這種形式。

文法

    ALTER TABLE [ IF EXISTS ] [ ONLY ] name [ * ]
        action [, ... ]
    ALTER TABLE [ IF EXISTS ] [ ONLY ] name [ * ]
        RENAME [ COLUMN ] column_name TO new_column_name
    ALTER TABLE [ IF EXISTS ] [ ONLY ] name [ * ]
        RENAME CONSTRAINT constraint_name TO new_constraint_name
    ALTER TABLE [ IF EXISTS ] name
        RENAME TO new_name
    ALTER TABLE [ IF EXISTS ] name
        SET SCHEMA new_schema
    ALTER TABLE ALL IN TABLESPACE name [ OWNED BY role_name [, ... ] ]
        SET TABLESPACE new_tablespace [ NOWAIT ]
    ALTER TABLE [ IF EXISTS ] name
        ATTACH PARTITION partition_name { FOR VALUES partition_bound_spec | DEFAULT }
    ALTER TABLE [ IF EXISTS ] name
        DETACH PARTITION partition_name

    其中action 是以下之一:

        ADD [ COLUMN ] [ IF NOT EXISTS ] column_name data_type [ COLLATE collation ] [ column_constraint [ ... ] ]
        DROP [ COLUMN ] [ IF EXISTS ] column_name [ RESTRICT | CASCADE ]
        ALTER [ COLUMN ] column_name [ SET DATA ] TYPE data_type [ COLLATE collation ] [ USING expression ]
        ALTER [ COLUMN ] column_name SET DEFAULT expression
        ALTER [ COLUMN ] column_name DROP DEFAULT
        ALTER [ COLUMN ] column_name { SET | DROP } NOT NULL
        ALTER [ COLUMN ] column_name DROP EXPRESSION [ IF EXISTS ]
        ALTER [ COLUMN ] column_name ADD GENERATED { ALWAYS | BY DEFAULT } AS IDENTITY [ ( sequence_options ) ]
        ALTER [ COLUMN ] column_name { SET GENERATED { ALWAYS | BY DEFAULT } | SET sequence_option | RESTART [ [ WITH ] restart ] } [...]
        ALTER [ COLUMN ] column_name DROP IDENTITY [ IF EXISTS ]
        ALTER [ COLUMN ] column_name SET STATISTICS integer
        ALTER [ COLUMN ] column_name SET ( attribute_option = value [, ... ] )
        ALTER [ COLUMN ] column_name RESET ( attribute_option [, ... ] )
        ALTER [ COLUMN ] column_name SET STORAGE { PLAIN | EXTERNAL | EXTENDED | MAIN }
        ADD table_constraint [ NOT VALID ]
        ADD table_constraint_using_index
        ALTER CONSTRAINT constraint_name [ DEFERRABLE | NOT DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ]
        VALIDATE CONSTRAINT constraint_name
        DROP CONSTRAINT [ IF EXISTS ]  constraint_name [ RESTRICT | CASCADE ]
        DISABLE TRIGGER [ trigger_name | ALL | USER ]
        ENABLE TRIGGER [ trigger_name | ALL | USER ]
        ENABLE REPLICA TRIGGER trigger_name
        ENABLE ALWAYS TRIGGER trigger_name
        DISABLE RULE rewrite_rule_name
        ENABLE RULE rewrite_rule_name
        ENABLE REPLICA RULE rewrite_rule_name
        ENABLE ALWAYS RULE rewrite_rule_name
        DISABLE ROW LEVEL SECURITY
        ENABLE ROW LEVEL SECURITY
        FORCE ROW LEVEL SECURITY
        NO FORCE ROW LEVEL SECURITY
        CLUSTER ON index_name
        SET WITHOUT CLUSTER
        SET WITHOUT OIDS
        SET TABLESPACE new_tablespace
        SET { LOGGED | UNLOGGED }
        SET ( storage_parameter [= value] [, ... ] )
        RESET ( storage_parameter [, ... ] )
        INHERIT parent_table
        NO INHERIT parent_table
        OF type_name
        NOT OF
        OWNER TO { new_owner | CURRENT_USER | SESSION_USER }
        REPLICA IDENTITY { DEFAULT | USING INDEX index_name | FULL | NOTHING }

    and partition_bound_spec is:

    IN ( partition_bound_expr [, ...] ) |
    FROM ( { partition_bound_expr | MINVALUE | MAXVALUE } [, ...] )
      TO ( { partition_bound_expr | MINVALUE | MAXVALUE } [, ...] ) |
    WITH ( MODULUS numeric_literal, REMAINDER numeric_literal )

    and column_constraint is:

    [ CONSTRAINT constraint_name ]
    { NOT NULL |
      NULL |
      CHECK ( expression ) [ NO INHERIT ] |
      DEFAULT default_expr |
      GENERATED ALWAYS AS ( generation_expr ) STORED |
      GENERATED { ALWAYS | BY DEFAULT } AS IDENTITY [ ( sequence_options ) ] |
      UNIQUE index_parameters |
      PRIMARY KEY index_parameters |
      REFERENCES reftable [ ( refcolumn ) ] [ MATCH FULL | MATCH PARTIAL | MATCH SIMPLE ]
        [ ON DELETE referential_action ] [ ON UPDATE referential_action ] }
    [ DEFERRABLE | NOT DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ]

    而table_constraint是:

    [ CONSTRAINT constraint_name ]
    { CHECK ( expression ) [ NO INHERIT ] |
      UNIQUE ( column_name [, ... ] ) index_parameters |
      PRIMARY KEY ( column_name [, ... ] ) index_parameters |
      EXCLUDE [ USING index_method ] ( exclude_element WITH operator [, ... ] ) index_parameters [ WHERE ( predicate ) ] |
      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 ]

    並且 table_constraint_using_index 是:

        [ CONSTRAINT constraint_name ]
        { UNIQUE | PRIMARY KEY } USING INDEX index_name
        [ DEFERRABLE | NOT DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ]

    UNIQUE、PRIMARY KEY以及EXCLUDE約束中的index_parameters是:

    [ INCLUDE ( column_name [, ... ] ) ]
    [ WITH ( storage_parameter [= value] [, ... ] ) ]
    [ USING INDEX TABLESPACE tablespace_name ]

    exclude_element in an EXCLUDE constraint is:

    { column_name | ( expression ) } [ opclass ] [ ASC | DESC ] [ NULLS { FIRST | LAST } ]

如果需要增加一個新的約束但是不希望長時間阻塞表更新,那麼使用現有索引增加約束會有所協助。要這樣做,用 CREATE INDEX CONCURRENTLY建立該索引,並且接著使用這種文法把它安裝為一個正式的約束。例子見下文。

ALTER CONSTRAINT這種形式修改之前建立的一個約束的屬性。當前只能修改外鍵約束。

VALIDATE CONSTRAINT這種形式驗證之前建立為NOT VALID的外鍵或檢查約束, 它會掃描表來確保對於該約束沒有行不滿足約束。如果約束已經被標記為合法,則什麼也不會發生。

DROP CONSTRAINT [ IF EXISTS ]這種形式在一個表上刪除指定的約束,還有位於該約束之下的任何索引。如果IF EXISTS 被指定並且該約束不存在,不會拋出錯誤。在這種情況下會發出一個提示。

DISABLE/ENABLE [ REPLICA | ALWAYS ] TRIGGER這些形式配置屬於該表的觸發器的觸發設定。系統仍然知道被禁用觸發器的存在,但是即使它的觸發事件發生也不會執行它。對於一個延遲觸發器, 會在事件發生時而不是觸發器函數真正被執行時檢查其啟用狀態。可以禁用或者啟用名稱指定的單個觸發器、表上的所有觸發器、使用者擁有的觸發器(這個選項會排除內部產生的約束觸發器,例如用來實現外鍵約束或可延遲唯一和排除約束)。禁用或者啟用內部產生的約束觸發器要求超級使用者特權,這樣做要小心因為如果這類觸發器不被執行,約束的完整性當然無法保證。

觸發器引發機制也受到組態變數 session_replication_role 的影響。當複製角色是 “origin”(預設)或者“local”時,被簡單啟用的觸發器將被觸發。被配置為ENABLE REPLICA的觸發器只有在會話處於“replica”模式時才將被觸發。被配置為 ENABLE ALWAYS的觸發器的觸發不會考慮當前複製角色。

這種機制的效果就是,在預設配置中,觸發器不會在複製體上引發。這種效果很有用,因為如果一個觸發器在源頭上被用來在表之間傳播資料,那麼複製系統也將複製被傳播的資料,並且觸發器不應該在複製體上引發第二次,因為那會導致重複。不過,如果一個觸發器被用於另一種目的(例如建立外部警示),那麼將它設定為ENABLE ALWAYS可能更加合適,這樣它在複製體上也會被引發。

這個命令要求一個SHARE ROW EXCLUSIVE鎖。

DISABLE/ENABLE [ REPLICA | ALWAYS ] RULE這些形式配置屬於表的重寫規則的觸發設定。系統仍然知道一個被禁用規則的存在,但在查詢重寫時不會應用它。其語義與禁用的/啟用的觸發器的一樣。 對於ON SELECT規則會忽略這個配置,即使當前會話處於一種非預設的複製角色,這類規則總是會被應用以保持視圖工作正常。

規則引發機制也受到組態變數 session_replication_role 的影響,這和上述的觸發器類似。

DISABLE/ENABLE ROW LEVEL SECURITY這些形式控制屬於該表的行安全性策略的應用。如果被啟用並且該表上不存在策略,則將應用一個預設否定的策略。即使行級安全性被禁用,在表上還是可以存在策略。在這種情況下,這些策略將不會被應用並且會被忽略。

NO FORCE/FORCE ROW LEVEL SECURITY這些形式控制當使用者是表擁有者時表上的行安全性策略的應用。如果被啟用, 當使用者是表擁有者時,行級安全性策略將被應用。如果被禁用(預設),則當使用者是表擁有者時,行級安全性將不會被應用。

CLUSTER ON這種形式為未來的 CLUSTER 操作選擇預設的索引。 它不會真正地對錶進行聚簇。

改變聚簇選項要求一個SHARE UPDATE EXCLUSIVE鎖。

SET WITHOUT CLUSTER這種形式從表中移除最近使用的 CLUSTER 索引說明。這會影響未來的不指定索引的聚簇操作。

改變聚簇選項要求一個SHARE UPDATE EXCLUSIVE鎖。

SET WITHOUT OIDS向後相容的文法,用於刪除oid系統列。由於oid系統列無法再添加,所以不會有實際效果。

SET TABLESPACE這種形式把該表的資料表空間更改為指定的資料表空間並且把該表相關聯的資料檔案移動到新的資料表空間中。表上的索引(如果有)不會被移動,但是它們可以用額外的SET TABLESPACE命令單獨移動。 當應用於分區表時,不會移動任何內容,但之後用CREATE TABLE PARTITION OF建立的任何分區將使用該資料表空間,除非被TABLESPACE子句覆蓋。

當前資料庫在一個資料表空間中的所有表可以用ALL IN TABLESPACE形式移動,這將會首先鎖住所有將被移動的表然後逐個移動。這種形式也支援 OWNED BY,它將只移動指定角色所擁有的表。如果指定了NOWAIT選項,則命令將在無法立刻獲得所有所需要的鎖時失敗。注意這個命令不移動系統目錄;如果想要移動系統目錄,應該用ALTER DATABASE或者顯式的 ALTER TABLE調用。對於這種形式來說, information_schema關係不被認為是系統目錄的一部分, 因此它們將會被移動。

SET { LOGGED | UNLOGGED }該ALTER將表在UNLOGGED與LOGGED之間進行轉換,但不能用於暫存資料表。

說明

由於當前架構無法支援UNLOGGED TABLE,因此在SET UNLOGGED操作時會出現報錯。

SET ( storage_parameter [= value ] [, ... ] )這種形式為該表更改一個或者更多儲存參數。可用的參數請見 Storage Parameters 的 CREATE TABLE 。這個命令將不會立刻修改表內容,這取決於重寫表以得到想要的結果可能需要的參數。可以用 VACUUM FULL、 CLUSTER 或者 ALTER TABLE的一種形式來強制一次表重寫。對於規劃器相關的參數,更改將從該表下一次被鎖定開始生效,因此當前執行的查詢不會受到影響。

對 fillfactor、toast 以及 autovacuum 儲存參數,將會拿取SHARE UPDATE EXCLUSIVE鎖,就像計劃器參數 parallel_workers

RESET ( storage_parameter [, ... ] )這種形式把一個或者更多儲存參數重設到它們的預設值。和 SET一樣,可能需要一次表重寫來更新整個表。

INHERIT parent_table這種形式把目標表增加為指定父表的一個新子女。隨後,針對父親的查詢將包括目標表中的記錄。要被增加為一個子女,目標表必須已經包含和父表完全相同的列(也可以有額外的列)。這些列必須具有匹配的資料類型,並且如果它們在父表中具有NOT NULL約束,它們在子表中也必須有NOT NULL約束。

也必須把子資料表條件約束與所有父表的CHECK約束進行匹配, 不過父表中那些被標記為非可繼承(也就是用ALTER TABLE ... ADD CONSTRAINT ... NO INHERIT 建立的)除外,它們會被忽略。所有匹配得上的子資料表條件約束不能被標記為不可繼承。當前,UNIQUEPRIMARY KEY 以及FOREIGN KEY約束沒有被考慮,但是這種情況可能會在未來發生變化。

NO INHERIT parent_table這種形式把目標表從指定父表的子女列表中移除。針對父表的查詢將不再包括來自目標表的記錄。

OF type_name這種形式把該錶鏈接到一種組合類別型,就好像CREATE TABLE OF所做的那樣。該表的列名和類型列表必須精確地匹配該組合類別型。 該表必須不從任何其他表繼承。這些限制確保CREATE TABLE OF能允許一個等價的表定義。

NOT OF這種形式解除一個有類型的表和其類型之間的關聯。

OWNER TO這種形式把表、序列、視圖、物化視圖或外部表格的擁有者改為指定使用者。

REPLICA IDENTITY這種形式更改被寫入到預寫式日誌來標識被更新或刪除行的資訊。除非使用邏輯複製, 這個選項將不會產生效果。DEFAULT(非系統資料表的預設值)記錄主鍵列 (如果有)的舊值。USING INDEX記錄被所提到的索引所覆蓋的列的舊值,該索引必須是唯一索引、不是部分索引、不是可延遲索引並且只包括被標記成 NOT NULL的列。FULL記錄行中所有列的舊值。 NOTHING不記錄有關舊行的任何資訊(這是系統資料表的預設值)。在所有情況下,除非至少有一個要被記錄的列在新舊行版本之間發生變化,將不記錄舊值。

RENAMERENAME形式更改一個表(或者一個索引、序列、視圖、物化視圖或者外部表格)的名稱、表中一個列的名稱或者表的一個約束的名稱。在重新命名一個具有底層索引的約束時,該索引也會被重新命名。它對已儲存的資料沒有影響。

SET SCHEMA這種形式把該表移動到另一個模式中。相關的該表列擁有的索引、約束和序列也會被移動。

ATTACH PARTITION partition_name { FOR VALUES partition_bound_spec | DEFAULT }這種形式把一個已有表(自身也可能被分區)作為一個分區掛接到目標表。該表可以為特定的值使用FOR VALUES掛接為分區,或者用DEFAULT掛接為一個預設分區。 對於目標表中的每一個索引,在被掛接的表上都將建立一個響應的索引,如果已經存在等效的索引,該索引將被掛接到目標表的索引,就像執行了ALTER INDEX ATTACH PARTITION一樣。 請注意,如果現有表是外表,如果目標表上有UNIQUE索引, 則當前不允許將表作為目標表的分區附加。對於目標表中存在的每個使用者定義的行級觸發器,將在附加表中建立一個對應的觸發器。

一個使用FOR VALUES的分區使用與 CREATE TABLE 中 partition_bound_spec相同的文法。分區邊界說明必須對應於目標表的分區策略以及分區鍵。要被掛接的表必須具有和目標表完全相同的所有列,並且不能有多出來的列,而且列的類型也必須匹配。此外,它必須有目標表上所有的NOT NULL以及CHECK約束。當前不考慮FOREIGN KEY約束。來自於父表的UNIQUEPRIMARY KEY約束將被建立在分區上(如果它們還不存在)。如果被掛接的表上的任何CHECK約束被標記為NO INHERIT,則命令將失敗,這類約束必須被重建且重建時不能有NO INHERIT子句。

如果新分區是一個常規表,會執行一次全表掃描來檢查表中現有行沒有違背分區約束。 可以通過對錶增加一個有效CHECK約束來避免這種掃描,該約束可以在運行這個命令之前僅允許滿足所需分區約束的行。 CHECK約束可以解決讓表無需被掃描就能驗證分區約束。但是,如果任一分區鍵是一個運算式並且該分區不接受NULL值,這種方式就無效了。 如果掛接一個不接受NULL值的列表分區,還應該為分區鍵列增加NOT NULL約束,除非它是一個運算式。

如果新分區是一個外部表格,則不需要驗證該外部表格中的所有行遵守分區約束。

當一個表有預設分區時,定義新分區會更改預設分區的分區約束。預設分區不能包含任何需要被移動到新分區中的行,並且將被掃描以驗證不存在那樣的行。如果一個合適的CHECK約束存在,這種掃描(和新分區的掃描一樣)可以被避免。還是和新分區的掃描一樣,當預設分區是外部表格時這種掃描總是會被跳過。

在父表上附加一個分區獲得一個SHARE UPDATE EXCLUSIVE鎖,除了要附加的表和預設分區上的ACCESS EXCLUSIVE 鎖(如果有)。

DETACH PARTITION partition_name這種形式會分離目標表的指定分區。被分離的分區繼續作為獨立的表存在,但是與它之前掛接的表不再有任何聯絡。任何被掛接到目標表索引的索引也會被分離。 任何作為目標表中那些表的複本建立的表也會被刪除。

除了RENAMESET SCHEMAATTACH PARTITIONDETACH PARTITION之外,所有形式的 ALTER TABLE 都作用在單個表上,前面這些形式可以被組合成一個多修改的列表被一起應用。例如,可以在一個命令中增加多個列並且/或者修改多個列的類型。對於大型表來說這會特別有用,因為只需要對錶做一趟操作。

要使用ALTER TABLE,你必須擁有該表。要更改一個表的模式或者資料表空間,你還必須擁有新模式或資料表空間上的 CREATE特權。要把一個表作為一個父表的新子表加入, 你必須也擁有該父表。此外,要把一個表掛接為另一個表的新分區,你必須擁有被掛接的表。要更改擁有者,你還必須是新擁有角色的一個直接或者間接成員,並且該角色必須具有該表的模式上的 CREATE特權(這些限制強制修改擁有者不能做一些通過刪除和重建表做不到的事情。不過,一個超級使用者怎麼都能更改任何錶的所有權。)。 要增加一個列、修改一列的類型或者使用OF子句,你還必須具有該資料類型上的USAGE特權。

參數

IF EXISTS如果表不存在則不要拋出一個錯誤。這種情況下會發出一個提示。

name要修改的一個現有表的名稱(可以是模式限定的)。如果在表名前指定了 ONLY,則只會修改該表。如果沒有指定ONLY, 該表及其所有後代表(如果有)都會被修改。可選地,在表名後面可以指定用來顯式地指示包括後代表。

column_name一個新列或者現有列的名稱。

new_column_name一個現有列的新名稱。

new_name該表的新名稱。

data_type一個新列的資料類型或者一個現有列的新資料類型。

table_constraint該表的新的資料表條件約束。

constraint_name一個新約束或者現有約束的名稱。

CASCADE自動刪除依賴於被刪除列或約束的對象(例如引用該列的視圖), 並且接著刪除依賴於那些對象的所有對象。

RESTRICT如果有任何依賴對象時拒絕刪除列或者約束。這是預設行為。

trigger_name一個要禁用或啟用的觸發器的名稱。

ALL禁用或者啟用屬於該表的所有觸發器(如果有任何觸發器是內部產生的約束觸發器則需要超級使用者特權,例如那些被用來實現外鍵約束或者可延遲一致性和排他約束的觸發器)。

USER禁用或者啟用屬於該表的所有觸發器,內部產生的約束觸發器(例如那些被用來實現外鍵約束或者可延遲一致性和排他約束的觸發器)除外。

index_name一個現有索引的名稱。

storage_parameter一個表格儲存體參數的名稱。

value一個表格儲存體參數的新值。根據該參數,該值可能是一個數字或者一個詞。

parent_table要與這個表關聯或者解除關聯的父表。

new_owner該表的新擁有者的使用者名稱。

new_tablespace要把該表移入其中的資料表空間的名稱。

new_schema要把該表移入其中的模式的名稱。

partition_name要被作為新分區附著到這個表或者從這個表上分離的表的名稱。

partition_bound_spec新分區的分區邊界說明。

說明

關鍵詞COLUMN可以被省略。

在使用ADD COLUMN增加一列並且指定了一個非易失性DEFAULT時,預設值會在該語句執行時計算並且結果會被儲存在表的中繼資料中。這個值將被用於所有現有行的該列。如果沒有指定DEFAULT,則使用 NULL。在兩種情況下都不需要重寫表。

增加一個帶有非易失性DEFAULT子句的列或者更改一個現有列的類型將要求重寫整個表及其索引。在更改一個現有列的類型時有一種例外:如果 USING子句不更改列的內容並且舊類型在二進位上與新類型可強制轉換或者是新類型上的一個未約束域,則不需要重寫表。但是受影響列上的任何索引仍必須被重建。對於一個大型表,表和/或索引重建可能會消耗相當多的時間, 並且會臨時要求差不多兩倍的磁碟空間。

增加一個CHECK或者NOT NULL約束要求掃描表以驗證現有行符合該約束,但是不要求一次表重寫。

類似地,在掛接一個新分區時,它需要被掃描以驗證現有行滿足該分區約束。

提供在一個ALTER TABLE中指定多個更改的選項的主要原因就是多次表掃描或者重寫可以因此被整合成一次。

掃描大型表以驗證新的外鍵或檢查約束可能需要很長時間,並且對錶的其他更新將鎖定,直到ALTER TABLE ADD CONSTRAINT命令被提交。 NOT VALID約束選項的主要目的是減少對並發更新添加約束的影響。 使用 NOT VALIDADD CONSTRAINT命令不掃描表,可以立即提交。 在之後,VALIDATE CONSTRAINT命令會被發出以驗證現有行是否滿足約束。 驗證步驟不需要鎖定並發更新,因為它知道其他事務將強制執行它們插入或更新的行的約束;只有預先存在的行需要檢查。 因此,驗證在被更改的表上僅獲得一個SHARE UPDATE EXCLUSIVE鎖。 (如果約束是外鍵,則 ROW SHARE鎖也需要約束的表引用。) 除了改進並發性外,在已知該表包含預先存在的違規行為的情況下使用 NOT VALIDVALIDATE CONSTRAINT也能有作用。 一旦約束就位,就不能再插入新的違規,並且現有問題可以在空閑時糾正,直到VALIDATE CONSTRAINT最終完成。

DROP COLUMN形式不會在物理上移除列,而只是簡單地讓它對 SQL 操作不可見。後續該表中的插入和更新操作將為該列儲存一個空值。因此,刪除一個列很快,但是它不會立刻減少表所佔的磁碟空間, 因為被刪除列所佔用的空間還沒有被回收。隨著現有列被更新,空間將被逐漸回收。

要強制立即回收被已刪除列佔據的空間,你可以執行一種能導致全表重寫的 ALTER TABLE形式。這種形式會導致重新構造每一個把被刪除列替換為空白值的行。

ALTER TABLE的重寫形式對於 MVCC 是不安全的。 在一次表重寫之後,如果並發事務使用的是一個在重寫發生前取得的快照,該表將對這些並發事務呈現出空表的形態。

SET DATA TYPEUSING選項能實際指定涉及該列舊值的任何錶達式。也就是說,它可以不但可以引用要被轉換的列, 還可以引用其他列。這允許使用SET DATA TYPE文法完成十分普遍的轉換。由於這種靈活性,USING運算式不適合於列的預設值(如果有),結果可能不是一個預設值所需的常量運算式。這意味著在沒有從舊類型到新類型的隱式或者賦值造型時,即便提供了一個 USING子句,SET DATA TYPE還是可能無法轉換預設值。在這種情況下,用DROP DEFAULT刪除該預設值, 執行ALTER TYPE並且接著使用SET DEFAULT增加一個合適的新預設值。類似的考慮也適用於涉及該列的索引和約束。

如果一個表有任何後代表,在不對後代表做相同操作的情況下,不允許在父表中增加列、重新命名列或者更改列的類型。這確保了後代總是具有和父表匹配的列。類似地,如果不對所有後代上的CHECK約束進行重新命名,就不能在父表中重新命名該CHECK約束,這樣CHECK約束也能在父表及其後代之間保持匹配(不過,這個限制不適用於基於索引的約束)。此外,因為從父表中選擇也會從其後代中選擇,父表上的約束不能被標記為有效,除非它在那些後代上也被標記為有效。在所有這些情況下,ALTER TABLE ONLY都將被拒絕。

只有當一個後代表的列不是從任何其他父表繼承而來並且沒有該列的獨立定義時, 一次遞迴的DROP COLUMN操作才會移除該列。一次非遞迴的DROP COLUMN(即 ALTER TABLE ONLY ... DROP COLUMN)不會移除任何後代列,而是會把它們標記成獨立定義的列。對於一個分區表,一個非遞迴的DROP COLUMN命令將會失敗,因為一個表的所有分區都必須有和分區根節點相同的列。

識別欄位的動作(ADD GENERATEDSET等、DROP IDENTITY)以及動作TRIGGERCLUSTEROWNERTABLESPACE不會遞迴到後代表上,也就是說它們執行時總是好像指定了ONLY一樣。增加約束的動作僅對沒有標記為NO INHERITCHECK約束遞迴。

不允許更改一個系統目錄表的任何部分。

樣本

向一個表增加一個類型為varchar的列:

    ALTER TABLE distributors ADD COLUMN address varchar(30);

這將導致表中所有現有行都用新列的空值填充。

添加預設值為非空的列:

    ALTER TABLE measurements
      ADD COLUMN mtime timestamp with time zone DEFAULT now();

現有行將以目前時間填充為新列的值,然後新行直將使用其插入時間。

添加一列並用不同於預設值的值填充它:

    ALTER TABLE transactions
      ADD COLUMN status varchar(30) DEFAULT 'old',
      ALTER COLUMN status SET default 'current';

現有行將用old填充,但是隨後的命令的預設值將是current。 其效果與在單獨的ALTER TABLE命令中發出兩個子命令的效果相同。

從表中刪除一列:

    ALTER TABLE distributors DROP COLUMN address RESTRICT;

在一個操作中更改兩個現有列的類型:

    ALTER TABLE distributors
        ALTER COLUMN address TYPE varchar(80),
        ALTER COLUMN name TYPE varchar(100);

通過一個USING子句更改一個包含 Unix 時間戳記的整數列為 timestamp with time zone

    ALTER TABLE foo
        ALTER COLUMN foo_timestamp SET DATA TYPE timestamp with time zone
        USING
            timestamp with time zone 'epoch' + foo_timestamp * interval '1 second';

同樣的,當該列具有一個不能自動造型成新資料類型的預設值運算式時:

    ALTER TABLE foo
        ALTER COLUMN foo_timestamp DROP DEFAULT,
        ALTER COLUMN foo_timestamp TYPE timestamp with time zone
        USING
            timestamp with time zone 'epoch' + foo_timestamp * interval '1 second',
        ALTER COLUMN foo_timestamp SET DEFAULT now();

重新命名一個現有的列:

    ALTER TABLE distributors RENAME COLUMN address TO city;

重新命名一個現有的表:

    ALTER TABLE distributors RENAME TO suppliers;

重新命名一個現有的約束:

    ALTER TABLE distributors RENAME CONSTRAINT zipchk TO zip_check;

為一列增加一個非空約束:

    ALTER TABLE distributors ALTER COLUMN street SET NOT NULL;

從一列移除一個非空約束:

    ALTER TABLE distributors ALTER COLUMN street DROP NOT NULL;

向一個表及其所有子女增加一個檢查約束:

    ALTER TABLE distributors ADD CONSTRAINT zipchk CHECK (char_length(zipcode) = 5);

只向一個表增加一個檢查約束(不為其子女增加):

    ALTER TABLE distributors ADD CONSTRAINT zipchk CHECK (char_length(zipcode) = 5) NO INHERIT;

(該檢查約束也不會被未來的子女繼承)。

從一個表及其子女移除一個檢查約束:

    ALTER TABLE distributors DROP CONSTRAINT zipchk;

只從一個表移除一個檢查約束:

    ALTER TABLE ONLY distributors DROP CONSTRAINT zipchk;

(該檢查約束仍為子女表保留在某個地方)。

為一個表增加一個外鍵約束:

    ALTER TABLE distributors ADD CONSTRAINT distfk FOREIGN KEY (address) REFERENCES addresses (address);

為一個表增加一個外鍵約束,並且盡量不要影響其他工作:

    ALTER TABLE distributors ADD CONSTRAINT distfk FOREIGN KEY (address) REFERENCES addresses (address) NOT VALID;
    ALTER TABLE distributors VALIDATE CONSTRAINT distfk;

為一個表增加一個(多列)唯一約束:

    ALTER TABLE distributors ADD CONSTRAINT dist_id_zipcode_key UNIQUE (dist_id, zipcode);

為一個表增加一個自動命名的主鍵約束,注意一個表只能擁有一個主鍵:

    ALTER TABLE distributors ADD PRIMARY KEY (dist_id);

把一個表移動到一個不同的資料表空間:

    ALTER TABLE distributors SET TABLESPACE fasttablespace;

把一個表移動到一個不同的模式:

    ALTER TABLE myschema.distributors SET SCHEMA yourschema;

重建一個主鍵約束,並且在重建索引期間不阻塞更新:

    CREATE UNIQUE INDEX CONCURRENTLY dist_id_temp_idx ON distributors (dist_id);
    ALTER TABLE distributors DROP CONSTRAINT distributors_pkey,
        ADD CONSTRAINT distributors_pkey PRIMARY KEY USING INDEX dist_id_temp_idx;

把一個分區掛接到一個定界分割表上:

    ALTER TABLE measurement
        ATTACH PARTITION measurement_y2016m07 FOR VALUES FROM ('2016-07-01') TO ('2016-08-01');

把一個分區掛接到一個列表分區表上:

    ALTER TABLE cities
        ATTACH PARTITION cities_ab FOR VALUES IN ('a', 'b');

把一個分區掛接到一個雜湊分割表上:

    ALTER TABLE orders
        ATTACH PARTITION orders_p4 FOR VALUES WITH (MODULUS 4, REMAINDER 3);

把一個預設分區掛接到一個分區表上:

    ALTER TABLE cities
        ATTACH PARTITION cities_partdef DEFAULT;

從一個分區表分離一個分區:

    ALTER TABLE measurement
        DETACH PARTITION measurement_y2015m12;