UPDATE — 更新表中的行
[ WITH [ RECURSIVE ]with_query
[, ...] ] UPDATE [ ONLY ]table_name
[ * ] [ [ AS ]alias
] SET {column_name
= {expression
| DEFAULT } | (column_name
[, ...] ) = [ ROW ] ( {expression
| DEFAULT } [, ...] ) | (column_name
[, ...] ) = (sub-SELECT
) } [, ...] [ FROMfrom_item
[, ...] ] [ WHEREcondition
| WHERE CURRENT OFcursor_name
] [ RETURNING [ WITH ( { OLD | NEW } ASoutput_alias
[, ...] ) ] { * |output_expression
[ [ AS ]output_name
] } [, ...] ]
UPDATE
更改表中滿足條件的行的指定列的值。只需要在 SET
子句中提及要修改的列;未顯式修改的列將保留其先前的值。
有兩種方法可以使用資料庫中其他表包含的資訊來修改表:使用子查詢,或在 FROM
子句中指定其他表。哪種技術更合適取決於具體情況。
可選的 RETURNING
子句會導致 UPDATE
在實際更新的每一行基礎上計算並返回值。任何使用該表列以及/或 FROM
中提及的其他表的列的表示式都可以被計算。預設情況下,使用該表列的新(更新後)值,但也可以請求舊(更新前)值。 RETURNING
列表的語法與 SELECT
的輸出列表的語法完全相同。
您必須擁有該表的 UPDATE
許可權,或者至少擁有列出要更新的列的 UPDATE
許可權。您還必須擁有對在 expressions
或 condition
中讀取的任何列的 SELECT
許可權。
with_query
WITH
子句允許您指定一個或多個可以在 UPDATE
查詢中透過名稱引用的子查詢。有關詳細資訊,請參閱 第 7.8 節 和 SELECT。
table_name
要更新的表的名稱(可選模式限定)。如果表名稱前指定了 ONLY
,則僅在命名的表中更新匹配的行。如果未指定 ONLY
,則在繼承自命名錶的任何表中也會更新匹配的行。可選地,可以在表名後指定 *
,以明確指示包含子表。
alias
目標表的替代名稱。當提供了別名時,它會完全隱藏表的實際名稱。例如,給定 UPDATE foo AS f
,UPDATE
語句的其餘部分必須將此表稱為 f
,而不是 foo
。
column_name
由 table_name
指定的表中的列的名稱。列名可以根據需要用子欄位名或陣列下標限定。在指定目標列時,請勿包含表名 — 例如,UPDATE table_name SET table_name.col = 1
是無效的。
expression
要賦給列的表示式。該表示式可以使用此列和其他列的舊值。
DEFAULT
將列設定為其預設值(如果未為其分配特定的預設表示式,則為 NULL)。標識列將被設定為由關聯序列生成的新值。對於生成列,指定此項是允許的,但僅指定了從生成表示式計算該列的正常行為。
sub-SELECT
一個 SELECT
子查詢,它生成與前面圓括號括起來的列列表一樣多的輸出列。子查詢在執行時必須只產生一行。如果它產生一行,則其列值將被賦給目標列;如果它不產生行,則將 NULL 值賦給目標列。子查詢可以引用要更新的表的當前行的舊值。
from_item
一個表表達式,允許其他表的列出現在 WHERE
條件和更新表示式中。這使用了與 SELECT
語句的 FROM
子句相同的語法;例如,可以為表名指定別名。不要將目標表作為 from_item
重複,除非您打算進行自連線(在這種情況下,它必須在 from_item
中帶別名出現)。
condition
一個返回 boolean
型別值的表示式。只有當此表示式返回 true
的行才會被更新。
cursor_name
在 WHERE CURRENT OF
條件中使用的遊標名稱。要更新的行是最近從該遊標中獲取的行。該遊標必須是對 UPDATE
的目標表執行的非分組查詢。注意 WHERE CURRENT OF
不能與布林條件一起指定。有關將遊標與 WHERE CURRENT OF
一起使用的更多資訊,請參閱 DECLARE。
output_alias
RETURNING
列表中的 OLD
或 NEW
行的可選替代名稱。
預設情況下,可以透過編寫 OLD.
或 column_name
OLD.*
返回目標表中的舊值,透過編寫 NEW.
或 column_name
NEW.*
返回新值。提供別名時,將隱藏這些名稱,並且必須使用別名引用舊行或新行。例如 RETURNING WITH (OLD AS o, NEW AS n) o.*, n.*
。
output_expression
在更新完每一行後由 UPDATE
命令計算並返回的表示式。該表示式可以使用 table_name
指定的表或 FROM
中列出的表中的任何列名。寫入 *
以返回所有列。
列名或 *
可以使用 OLD
或 NEW
,或者 OLD
或 NEW
的相應 output_alias
進行限定,以返回舊值或新值。未限定的列名、*
,或使用目標表名或別名限定的列名或 *
將返回新值。
output_name
用於返回列的名稱。
成功完成後,UPDATE
命令返回一個命令標籤,格式為
UPDATE count
count
是更新的行數,包括值未更改的匹配行。請注意,當更新被 BEFORE UPDATE
觸發器抑制時,該數字可能小於匹配 condition
的行數。如果 count
為 0,則查詢未更新任何行(這不被視為錯誤)。
如果 UPDATE
命令包含 RETURNING
子句,結果將類似於包含 RETURNING
列表中定義的列和值的 SELECT
語句,該語句在命令更新的行上進行計算。
當存在 FROM
子句時,實際上發生的是目標表與 from_item
列表中的表連線,並且連線的每一輸出行代表目標表的一個更新操作。使用 FROM
時,您應確保連線最多為每個要修改的行產生一行輸出。換句話說,目標行不應連線到其他表中的多個行。如果這樣做,將只使用其中一個連線行來更新目標行,但具體使用哪一個行是不可預測的。
由於這種不確定性,僅在子查詢中引用其他表更安全,儘管通常比使用連線更難讀且速度更慢。
對於分割槽表,更新一行可能會導致它不再滿足包含分割槽的分割槽約束。在這種情況下,如果分割槽樹中存在另一個分割槽,該行滿足其分割槽約束,則該行將被移動到該分割槽。如果不存在這樣的分割槽,則會發生錯誤。在後臺,行移動實際上是 DELETE
和 INSERT
操作。
在移動的行上可能發生併發 UPDATE
或 DELETE
操作,從而導致序列化失敗錯誤。假設會話 1 正在對分割槽鍵執行 UPDATE
,而此時併發會話 2(該行對該會話可見)正在對該行執行 UPDATE
或 DELETE
操作。在這種情況下,會話 2 的 UPDATE
或 DELETE
將檢測到行移動並引發序列化失敗錯誤(該錯誤始終返回 SQLSTATE 程式碼 '40001')。應用程式可能希望在這種情況下重試事務。在通常情況下(表未分割槽,或沒有行移動),會話 2 將識別出新更新的行,並對這個新的行版本執行 UPDATE
/DELETE
。
請注意,雖然行可以從本地分割槽移動到外部表分割槽(前提是外部資料包裝器支援元組路由),但它們不能從外部表分割槽移動到其他分割槽。
如果外部索引鍵直接引用源分割槽的祖先,而該祖先與 UPDATE
查詢中提到的祖先不是同一個,那麼嘗試將行從一個分割槽移動到另一個分割槽將失敗。
將 films
表的 kind
列中的單詞 Drama
更改為 Dramatic
UPDATE films SET kind = 'Dramatic' WHERE kind = 'Drama';
調整 weather
表中一行資料的溫度記錄,並將降水量重置為其預設值
UPDATE weather SET temp_lo = temp_lo+1, temp_hi = temp_lo+15, prcp = DEFAULT WHERE city = 'San Francisco' AND date = '2003-07-03';
執行相同操作,並返回更新後的條目和舊的降水量值
UPDATE weather SET temp_lo = temp_lo+1, temp_hi = temp_lo+15, prcp = DEFAULT WHERE city = 'San Francisco' AND date = '2003-07-03' RETURNING temp_lo, temp_hi, prcp, old.prcp AS old_prcp;
使用替代的列列表語法執行相同的更新
UPDATE weather SET (temp_lo, temp_hi, prcp) = (temp_lo+1, temp_lo+15, DEFAULT) WHERE city = 'San Francisco' AND date = '2003-07-03';
使用 FROM
子句語法,增加管理 Acme Corporation 客戶的銷售人員的銷售額計數
UPDATE employees SET sales_count = sales_count + 1 FROM accounts WHERE accounts.name = 'Acme Corporation' AND employees.id = accounts.sales_person;
使用 WHERE
子句中的子查詢執行相同的操作
UPDATE employees SET sales_count = sales_count + 1 WHERE id = (SELECT sales_person FROM accounts WHERE name = 'Acme Corporation');
更新客戶表中的聯絡人姓名,以匹配當前分配的銷售人員
UPDATE accounts SET (contact_first_name, contact_last_name) = (SELECT first_name, last_name FROM employees WHERE employees.id = accounts.sales_person);
使用連線也可以實現類似的結果
UPDATE accounts SET contact_first_name = first_name, contact_last_name = last_name FROM employees WHERE employees.id = accounts.sales_person;
然而,第二個查詢可能會產生意外結果,如果 employees
.id
不是唯一鍵,而第一個查詢保證會報錯(如果有多個 id
匹配)。此外,如果某個 accounts
.sales_person
條目沒有匹配項,第一個查詢會將相應的姓名欄位設定為 NULL,而第二個查詢則根本不會更新該行。
更新彙總表中的統計資訊以匹配當前資料
UPDATE summary s SET (sum_x, sum_y, avg_x, avg_y) = (SELECT sum(x), sum(y), avg(x), avg(y) FROM data d WHERE d.group_id = s.group_id);
嘗試插入新的庫存項及其庫存數量。如果該項已存在,則更新現有項的庫存計數。為了不使整個事務失敗,請使用儲存點
BEGIN; -- other operations SAVEPOINT sp1; INSERT INTO wines VALUES('Chateau Lafite 2003', '24'); -- Assume the above fails because of a unique key violation, -- so now we issue these commands: ROLLBACK TO sp1; UPDATE wines SET stock = stock + 24 WHERE winename = 'Chateau Lafite 2003'; -- continue with other operations, and eventually COMMIT;
更改 films
表在遊標 c_films
當前定位的行上的 kind
列
UPDATE films SET kind = 'Dramatic' WHERE CURRENT OF c_films;
影響多行的更新可能會對系統性能產生負面影響,例如表膨脹、複製延遲增加以及鎖爭用增加。在這種情況下,可以考慮分批執行操作,並在批次之間對錶執行 VACUUM
操作。雖然 UPDATE
沒有 LIMIT
子句,但可以透過使用 通用表表達式 和自連線來實現類似效果。使用標準的 PostgreSQL 表訪問方法,對系統列 ctid 的自連線非常高效
WITH exceeded_max_retries AS ( SELECT w.ctid FROM work_item AS w WHERE w.status = 'active' AND w.num_retries > 10 ORDER BY w.retry_timestamp FOR UPDATE LIMIT 5000 ) UPDATE work_item SET status = 'failed' FROM exceeded_max_retries AS emr WHERE work_item.ctid = emr.ctid;
此命令需要重複執行,直到沒有剩餘的行需要更新。使用 ORDER BY
子句可以使命令優先更新哪些行;如果其他更新操作使用相同的排序,它還可以防止與其他更新操作發生死鎖。如果擔心鎖爭用,則可以在CTE中新增 SKIP LOCKED
,以防止多個命令更新同一行。但是,然後需要一個沒有 SKIP LOCKED
或 LIMIT
的最終 UPDATE
,以確保沒有匹配的行被遺漏。
此命令符合SQL標準,除了 FROM
和 RETURNING
子句是 PostgreSQL 擴充套件,WITH
與 UPDATE
一起使用也是如此。
其他一些資料庫系統提供了 FROM
選項,其中目標表應再次列在 FROM
中。 PostgreSQL 的 FROM
的解釋並非如此。在移植使用此擴充套件的應用程式時要小心。
根據標準,目標列名圓括號括起來的子列表的源值可以是產生正確數量列的任何行值表示式。 PostgreSQL 只允許源值為 行構造器 或子 SELECT
。在行構造器的情況下,單個列的更新值可以指定為 DEFAULT
,但在子 SELECT
中不行。
如果您在文件中發現任何不正確、與您對特定功能的經驗不符或需要進一步澄清的內容,請使用 此表單 來報告文件問題。