支援的版本:目前 (17) / 16 / 15 / 14 / 13
開發版本:devel
不支援的版本:12 / 11 / 10 / 9.6 / 9.5 / 9.4 / 9.3 / 9.2 / 9.1 / 9.0 / 8.4 / 8.3 / 8.2 / 8.1 / 8.0 / 7.4 / 7.3 / 7.2 / 7.1

INSERT

INSERT — 在資料表中建立新的資料列

概要

[ WITH [ RECURSIVE ] with_query [, ...] ]
INSERT INTO table_name [ AS alias ] [ ( column_name [, ...] ) ]
    [ OVERRIDING { SYSTEM | USER } VALUE ]
    { DEFAULT VALUES | VALUES ( { expression | DEFAULT } [, ...] ) [, ...] | query }
    [ ON CONFLICT [ conflict_target ] conflict_action ]
    [ RETURNING { * | output_expression [ [ AS ] output_name ] } [, ...] ]

where conflict_target can be one of:

    ( { index_column_name | ( index_expression ) } [ COLLATE collation ] [ opclass ] [, ...] ) [ WHERE index_predicate ]
    ON CONSTRAINT constraint_name

and conflict_action is one of:

    DO NOTHING
    DO UPDATE SET { column_name = { expression | DEFAULT } |
                    ( column_name [, ...] ) = [ ROW ] ( { expression | DEFAULT } [, ...] ) |
                    ( column_name [, ...] ) = ( sub-SELECT )
                  } [, ...]
              [ WHERE condition ]

描述

INSERT 將新的資料列插入資料表中。可以插入由值表達式指定的一或多個資料列,或者插入查詢產生的零或多個資料列。

目標欄位的名稱可以按任何順序列出。如果沒有給出欄位名稱的清單,預設情況下將會使用資料表中所有欄位,並按照宣告的順序排列;或者,如果 VALUES 子句或 query 僅提供 N 個欄位,則使用前 N 個欄位名稱。VALUES 子句或 query 提供的值會從左到右與明確或隱含的欄位清單相關聯。

未出現在明確或隱含欄位清單中的每個欄位都將填入預設值,可以是其宣告的預設值,如果沒有,則填入 null。

如果任何欄位的表達式不是正確的資料類型,將會嘗試自動類型轉換。

向缺少唯一索引的資料表中執行 INSERT 不會被並行活動所阻擋。如果並行會話執行鎖定或修改與正在插入的唯一索引值相符的資料列的操作,則具有唯一索引的資料表可能會被阻擋;詳細資訊請參閱第 62.5 節ON CONFLICT 可用於指定替代動作,以避免引發唯一約束或排除約束違規錯誤。(請參閱下面的ON CONFLICT 子句。)

可選的 RETURNING 子句會導致 INSERT 計算並傳回基於每個實際插入(或更新,如果使用了 ON CONFLICT DO UPDATE 子句)的資料列的值。這主要用於獲取由預設值(例如序列號)提供的值。但是,允許使用任何使用資料表欄位的表達式。RETURNING 清單的語法與 SELECT 的輸出清單相同。只會傳回成功插入或更新的資料列。例如,如果由於 ON CONFLICT DO UPDATE ... WHERE 子句 condition 未滿足而鎖定但未更新資料列,則不會傳回該資料列。

您必須擁有資料表的 INSERT 權限才能向其中插入資料。如果存在 ON CONFLICT DO UPDATE,則還需要資料表的 UPDATE 權限。

如果指定了欄位清單,您只需要列出的欄位的 INSERT 權限。同樣,當指定 ON CONFLICT DO UPDATE 時,您只需要列出的要更新的欄位的 UPDATE 權限。但是,ON CONFLICT DO UPDATE 還需要 SELECT 權限,才能讀取 ON CONFLICT DO UPDATE 表達式或 condition 中值的任何欄位。

使用 RETURNING 子句需要 SELECT 權限才能存取 RETURNING 中提及的所有欄位。如果您使用 query 子句從查詢中插入資料列,那麼您當然需要對查詢中使用的任何資料表或欄位具有 SELECT 權限。

參數

插入

本節介紹僅在插入新資料列時可以使用的參數。ON CONFLICT 子句一起使用的參數將另行描述。

with_query

WITH 子句允許您指定一或多個子查詢,這些子查詢可以在 INSERT 查詢中通過名稱引用。有關詳細資訊,請參閱第 7.8 節SELECT

querySELECT 語句)也可能包含 WITH 子句。在這種情況下,兩組 with_query 都可以被 query 引用,但第二組優先,因為它的嵌套更深。

table_name

現有資料表的名稱(可選帶有結構描述限定詞)。

alias

替代的 table_name 名稱。 當提供別名時,它會完全隱藏表格的實際名稱。 這在 ON CONFLICT DO UPDATE 以名為 excluded 的表格為目標時特別有用,因為否則這會被視為代表要插入列的特殊表格的名稱。

column_name

table_name 命名的表格中的欄位名稱。 如果需要,欄位名稱可以用子欄位名稱或陣列下標進行限定。(僅插入複合欄位的某些欄位會使其他欄位為 null。)當使用 ON CONFLICT DO UPDATE 引用欄位時,請勿在目標欄位的規範中包含表格的名稱。 例如,INSERT INTO table_name ... ON CONFLICT DO UPDATE SET table_name.col = 1 無效(這遵循 UPDATE 的一般行為)。

OVERRIDING SYSTEM VALUE

如果指定了此子句,則為識別欄位提供的任何值都將覆蓋預設的序列產生值。

對於定義為 GENERATED ALWAYS 的識別欄位,如果沒有指定 OVERRIDING SYSTEM VALUEOVERRIDING USER VALUE,則插入明確的值(除了 DEFAULT)會發生錯誤。(對於定義為 GENERATED BY DEFAULT 的識別欄位,OVERRIDING SYSTEM VALUE 是正常行為,指定它沒有任何作用,但是 PostgreSQL 允許它作為擴充功能。)

OVERRIDING USER VALUE

如果指定了此子句,則為識別欄位提供的任何值都將被忽略,並且將應用預設的序列產生值。

例如,當在表格之間複製值時,此子句很有用。 寫入 INSERT INTO tbl2 OVERRIDING USER VALUE SELECT * FROM tbl1 將從 tbl1 複製所有不是 tbl2 中識別欄位的欄位,而 tbl2 中識別欄位的值將由與 tbl2 相關聯的序列產生。

DEFAULT VALUES

所有欄位都將填充其預設值,就像為每個欄位明確指定了 DEFAULT 一樣。(在此形式中不允許使用 OVERRIDING 子句。)

expression

要指派給對應欄位的表達式或值。

DEFAULT

對應的欄位將填充其預設值。 識別欄位將填充由關聯序列產生的新值。 對於產生的欄位,允許指定此項,但僅指定從其產生表達式計算欄位的正常行為。

query

提供要插入的列的查詢(SELECT 語句)。 有關語法的描述,請參閱 SELECT 語句。

output_expression

在插入或更新每一列之後,要由 INSERT 命令計算並返回的表達式。 該表達式可以使用由 table_name 命名的表格的任何欄位名稱。 寫入 * 以返回已插入或更新列的所有欄位。

output_name

用於返回欄位的名稱。

ON CONFLICT 子句

可選的 ON CONFLICT 子句指定了一個替代操作,以避免引發唯一性違規或排除約束違規錯誤。 對於每個提議要插入的單獨列,要麼插入繼續進行,要麼,如果違反了由 conflict_target 指定的 仲裁 約束或索引,則採取替代的 conflict_actionON CONFLICT DO NOTHING 只是避免插入作為替代操作的列。ON CONFLICT DO UPDATE 更新與提議插入的列衝突的現有列作為其替代操作。

conflict_target 可以執行 唯一索引推斷。 執行推斷時,它由一個或多個 index_column_name 欄位和/或 index_expression 表達式以及一個可選的 index_predicate 組成。 所有 table_name 唯一索引,無論順序如何,都包含完全由 conflict_target 指定的欄位/表達式,都被推斷(選擇)為仲裁索引。 如果指定了 index_predicate,則它必須作為推斷的進一步要求來滿足仲裁索引。 請注意,這表示如果存在滿足其他所有條件的非部分唯一索引(沒有謂詞的唯一索引),則將推斷(並因此被 ON CONFLICT 使用)此類索引。 如果推斷嘗試失敗,則會引發錯誤。

ON CONFLICT DO UPDATE 保證原子性的 INSERTUPDATE 結果; 只要沒有獨立錯誤,即使在高併發下,也保證這兩個結果之一。 這也稱為 UPSERTUPDATE or INSERT

conflict_target

通過選擇 仲裁索引,指定 ON CONFLICT 對哪些衝突採取替代操作。 要麼執行 唯一索引推斷,要麼明確命名約束。 對於 ON CONFLICT DO NOTHING,可以選擇指定 conflict_target; 如果省略,則會處理與所有可用約束(和唯一索引)的衝突。 對於 ON CONFLICT DO UPDATE必須 提供 conflict_target

conflict_action

conflict_action 指定替代的 ON CONFLICT 操作。 它可以是 DO NOTHING,也可以是 DO UPDATE 子句,該子句指定在發生衝突時要執行的 UPDATE 操作的確切詳細信息。ON CONFLICT DO UPDATE 中的 SETWHERE 子句可以使用表格的名稱(或別名)訪問現有列,並使用特殊的 excluded 表格訪問提議插入的列。 需要對目標表格中讀取相應 excluded 欄位的任何欄位具有 SELECT 權限。

請注意,所有按列 BEFORE INSERT 觸發器的效果都反映在 excluded 值中,因為這些效果可能導致該列被排除在插入之外。

index_column_name

table_name 欄位的名稱。 用於推斷仲裁索引。 遵循 CREATE INDEX 格式。 需要對 index_column_name 具有 SELECT 權限。

index_expression

index_column_name 類似,但用於推斷出現在索引定義中的 table_name 欄位上的表達式(而不是簡單欄位)。 遵循 CREATE INDEX 格式。 需要對出現在 index_expression 中的任何欄位具有 SELECT 權限。

collation

指定後,要求相應的 index_column_nameindex_expression 使用特定的定序,以便在推斷期間進行匹配。 通常會省略此項,因為定序通常不會影響是否發生約束衝突。 遵循 CREATE INDEX 格式。

opclass

若有指定,則強制對應的 index_column_nameindex_expression 使用特定的運算子類別,以便在推斷過程中進行匹配。通常會省略此項,因為 相等性 的語意在類型的運算子類別之間通常是等效的,或者因為信任已定義的唯一索引具有相關的相等性定義就已足夠。遵循 CREATE INDEX 格式。

index_predicate

用於允許推斷部分唯一索引。可以推斷出滿足謂詞的任何索引(不需要是部分索引)。遵循 CREATE INDEX 格式。需要對 index_predicate 中出現的任何欄位具有 SELECT 權限。

constraint_name

明確地按名稱指定仲裁 約束,而不是推斷約束或索引。

condition

一個傳回 boolean 類型值的表達式。只有此表達式傳回 true 的列才会被更新,儘管在執行 ON CONFLICT DO UPDATE 動作時,所有列都會被鎖定。請注意,在衝突被識別為更新候選對象之後,才會最後評估 condition

請注意,排除約束不支持作為 ON CONFLICT DO UPDATE 的仲裁者。在所有情況下,只有 NOT DEFERRABLE 約束和唯一索引才支持作為仲裁者。

帶有 ON CONFLICT DO UPDATE 子句的 INSERT 是一個確定性的語句。這意味著不允許該命令影響任何單個現有列超過一次;當出現這種情況時,將引發基數違規錯誤。建議插入的列在由仲裁索引或約束所約束的屬性方面不應重複。

請注意,目前不支持將應用於分割表的 INSERTON CONFLICT DO UPDATE 子句,來更新衝突列的分割鍵,使其需要將該列移動到新的分割區。

提示

通常最好使用唯一索引推斷,而不是直接使用 ON CONFLICT ON CONSTRAINT constraint_name 來命名約束。當使用 CREATE UNIQUE INDEX ... CONCURRENTLY 並在刪除被替換的索引之前,以重疊的方式用另一個或多或少等效的索引替換底層索引時,推斷將繼續正常工作。

輸出

成功完成後,INSERT 命令會傳回以下形式的命令標籤

INSERT oid count

count 是插入或更新的列數。oid 始終為 0(以前是OID如果 count 恰好為 1 且目標表格宣告為 WITH OIDS,則分配給插入的列,否則為 0,但不再支持建立 WITH OIDS 的表格)。

如果 INSERT 命令包含 RETURNING 子句,則結果將與包含 RETURNING 清單中定義的欄位和值的 SELECT 語句類似,這些欄位和值是透過該命令插入或更新的列計算得出。

注意事項

如果指定的表格是分割表格,則每一列都會被路由到適當的分割區並插入其中。如果指定的表格是分割區,則如果其中一個輸入列違反了分割區約束,則會發生錯誤。

您可能還希望考慮使用 MERGE,因為它允許在單個語句中混合使用 INSERTUPDATEDELETE。請參閱 MERGE

範例

將單個列插入表格 films

INSERT INTO films VALUES
    ('UA502', 'Bananas', 105, '1971-07-13', 'Comedy', '82 minutes');

在此範例中,省略了 len 欄位,因此它將具有預設值

INSERT INTO films (code, title, did, date_prod, kind)
    VALUES ('T_601', 'Yojimbo', 106, '1961-06-16', 'Drama');

此範例對日期欄位使用 DEFAULT 子句,而不是指定值

INSERT INTO films VALUES
    ('UA502', 'Bananas', 105, DEFAULT, 'Comedy', '82 minutes');
INSERT INTO films (code, title, did, date_prod, kind)
    VALUES ('T_601', 'Yojimbo', 106, DEFAULT, 'Drama');

要插入完全由預設值組成的列

INSERT INTO films DEFAULT VALUES;

要使用多列 VALUES 語法插入多個列

INSERT INTO films (code, title, did, date_prod, kind) VALUES
    ('B6717', 'Tampopo', 110, '1985-02-10', 'Comedy'),
    ('HG120', 'The Dinner Game', 140, DEFAULT, 'Comedy');

此範例從與 films 具有相同欄位佈局的表格 tmp_films 中將一些列插入表格 films

INSERT INTO films SELECT * FROM tmp_films WHERE date_prod < '2004-05-07';

此範例插入到陣列欄位中

-- Create an empty 3x3 gameboard for noughts-and-crosses
INSERT INTO tictactoe (game, board[1:3][1:3])
    VALUES (1, '{{" "," "," "},{" "," "," "},{" "," "," "}}');
-- The subscripts in the above example aren't really needed
INSERT INTO tictactoe (game, board)
    VALUES (2, '{{X," "," "},{" ",O," "},{" ",X," "}}');

將單個列插入表格 distributors,傳回由 DEFAULT 子句產生的序號

INSERT INTO distributors (did, dname) VALUES (DEFAULT, 'XYZ Widgets')
   RETURNING did;

增加為 Acme Corporation 管理帳戶的業務員的銷售額,並將整個更新的列以及目前時間記錄在日誌表格中

WITH upd AS (
  UPDATE employees SET sales_count = sales_count + 1 WHERE id =
    (SELECT sales_person FROM accounts WHERE name = 'Acme Corporation')
    RETURNING *
)
INSERT INTO employees_log SELECT *, current_timestamp FROM upd;

視情況插入或更新新的經銷商。假設已定義一個唯一索引,該索引約束了 did 欄位中顯示的值。請注意,特殊的 excluded 表格用於參考最初建議插入的值

INSERT INTO distributors (did, dname)
    VALUES (5, 'Gizmo Transglobal'), (6, 'Associated Computing, Inc')
    ON CONFLICT (did) DO UPDATE SET dname = EXCLUDED.dname;

插入經銷商,或在存在現有的、被排除的列(在觸發器觸發列插入之前,具有匹配的約束欄位或欄位的列)時,對建議插入的列不執行任何操作。範例假設已定義一個唯一索引,該索引約束了 did 欄位中顯示的值

INSERT INTO distributors (did, dname) VALUES (7, 'Redline GmbH')
    ON CONFLICT (did) DO NOTHING;

視情況插入或更新新的經銷商。範例假設已定義一個唯一索引,該索引約束了 did 欄位中顯示的值。WHERE 子句用於限制實際更新的列(儘管任何未更新的現有列仍將被鎖定)

-- Don't update existing distributors based in a certain ZIP code
INSERT INTO distributors AS d (did, dname) VALUES (8, 'Anvil Distribution')
    ON CONFLICT (did) DO UPDATE
    SET dname = EXCLUDED.dname || ' (formerly ' || d.dname || ')'
    WHERE d.zipcode <> '21201';

-- Name a constraint directly in the statement (uses associated
-- index to arbitrate taking the DO NOTHING action)
INSERT INTO distributors (did, dname) VALUES (9, 'Antwerp Design')
    ON CONFLICT ON CONSTRAINT distributors_pkey DO NOTHING;

如果可能,插入新的經銷商;否則 DO NOTHING。範例假設已定義一個唯一索引,該索引約束了 is_active 布林值欄位評估為 true 的列子集中 did 欄位中顯示的值

-- This statement could infer a partial unique index on "did"
-- with a predicate of "WHERE is_active", but it could also
-- just use a regular unique constraint on "did"
INSERT INTO distributors (did, dname) VALUES (10, 'Conrad International')
    ON CONFLICT (did) WHERE is_active DO NOTHING;

相容性

INSERT 符合 SQL 標準,但 RETURNING 子句是 PostgreSQL 擴充功能,如同將 WITHINSERT 一起使用的能力,以及使用 ON CONFLICT 指定替代操作的能力。此外,省略欄位名稱清單,但並非所有欄位都從 VALUES 子句或 query 填寫的情況,標準是不允許的。如果您希望比 ON CONFLICT 更符合 SQL 標準的語句,請參閱 MERGE

SQL 標準明確指出,只有在「總是產生」的身分欄位存在時,才能指定 OVERRIDING SYSTEM VALUE。 PostgreSQL 允許在任何情況下使用此子句,如果它不適用,則會忽略它。

關於 query 子句可能的限制,請參考 SELECT 的說明。

提交更正

如果您在文件中發現任何不正確、與您使用特定功能的經驗不符,或需要進一步澄清的地方,請使用此表單回報文件問題。