INSERT — 在資料表中建立新的資料列
[ WITH [ RECURSIVE ]with_query
[, ...] ] INSERT INTOtable_name
[ ASalias
] [ (column_name
[, ...] ) ] [ OVERRIDING { SYSTEM | USER } VALUE ] { DEFAULT VALUES | VALUES ( {expression
| DEFAULT } [, ...] ) [, ...] |query
} [ ON CONFLICT [conflict_target
]conflict_action
] [ RETURNING { * |output_expression
[ [ AS ]output_name
] } [, ...] ] whereconflict_target
can be one of: ( {index_column_name
| (index_expression
) } [ COLLATEcollation
] [opclass
] [, ...] ) [ WHEREindex_predicate
] ON CONSTRAINTconstraint_name
andconflict_action
is one of: DO NOTHING DO UPDATE SET {column_name
= {expression
| DEFAULT } | (column_name
[, ...] ) = [ ROW ] ( {expression
| DEFAULT } [, ...] ) | (column_name
[, ...] ) = (sub-SELECT
) } [, ...] [ WHEREcondition
]
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。
query
(SELECT
語句)也可能包含 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 VALUE
或 OVERRIDING 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_action
。ON 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
保證原子性的 INSERT
或 UPDATE
結果; 只要沒有獨立錯誤,即使在高併發下,也保證這兩個結果之一。 這也稱為 UPSERT — “UPDATE 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
中的 SET
和 WHERE
子句可以使用表格的名稱(或別名)訪問現有列,並使用特殊的 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_name
或 index_expression
使用特定的定序,以便在推斷期間進行匹配。 通常會省略此項,因為定序通常不會影響是否發生約束衝突。 遵循 CREATE INDEX
格式。
opclass
若有指定,則強制對應的 index_column_name
或 index_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
是一個「確定性的」語句。這意味著不允許該命令影響任何單個現有列超過一次;當出現這種情況時,將引發基數違規錯誤。建議插入的列在由仲裁索引或約束所約束的屬性方面不應重複。
請注意,目前不支持將應用於分割表的 INSERT
的 ON CONFLICT DO UPDATE
子句,來更新衝突列的分割鍵,使其需要將該列移動到新的分割區。
通常最好使用唯一索引推斷,而不是直接使用 ON CONFLICT ON CONSTRAINT
constraint_name
來命名約束。當使用 CREATE UNIQUE INDEX ... CONCURRENTLY
並在刪除被替換的索引之前,以重疊的方式用另一個或多或少等效的索引替換底層索引時,推斷將繼續正常工作。
成功完成後,INSERT
命令會傳回以下形式的命令標籤
INSERToid
count
count
是插入或更新的列數。oid
始終為 0(以前是OID如果 count
恰好為 1 且目標表格宣告為 WITH OIDS
,則分配給插入的列,否則為 0,但不再支持建立 WITH OIDS
的表格)。
如果 INSERT
命令包含 RETURNING
子句,則結果將與包含 RETURNING
清單中定義的欄位和值的 SELECT
語句類似,這些欄位和值是透過該命令插入或更新的列計算得出。
如果指定的表格是分割表格,則每一列都會被路由到適當的分割區並插入其中。如果指定的表格是分割區,則如果其中一個輸入列違反了分割區約束,則會發生錯誤。
您可能還希望考慮使用 MERGE
,因為它允許在單個語句中混合使用 INSERT
、UPDATE
和 DELETE
。請參閱 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 擴充功能,如同將 WITH
與 INSERT
一起使用的能力,以及使用 ON CONFLICT
指定替代操作的能力。此外,省略欄位名稱清單,但並非所有欄位都從 VALUES
子句或 query
填寫的情況,標準是不允許的。如果您希望比 ON CONFLICT
更符合 SQL 標準的語句,請參閱 MERGE。
SQL 標準明確指出,只有在「總是產生」的身分欄位存在時,才能指定 OVERRIDING SYSTEM VALUE
。 PostgreSQL 允許在任何情況下使用此子句,如果它不適用,則會忽略它。
關於 query
子句可能的限制,請參考 SELECT 的說明。
如果您在文件中發現任何不正確、與您使用特定功能的經驗不符,或需要進一步澄清的地方,請使用此表單回報文件問題。