这个问题很老,但是我觉得还没有给出最好的答案。
是否有UPDATE
语法... 未指定列名?
动态SQL的一般解决方案
您不需要知道任何列名,只需加入一些唯一的列即可(id
在示例中)。我可以想到的任何可能的情况都可以可靠地工作。
这是特定于PostgreSQL的。我正在基于information_schema构建动态代码,特别information_schema.columns
是基于SQL标准中定义的table的表,并且大多数主要的RDBMS(Oracle除外)都有它。但是DO
带有执行动态SQL的PL / pgSQL代码的语句完全是非标准的PostgreSQL语法。
DO
$do$
BEGIN
EXECUTE (
SELECT
'UPDATE b
SET (' || string_agg( quote_ident(column_name), ',') || ')
= (' || string_agg('a.' || quote_ident(column_name), ',') || ')
FROM a
WHERE b.id = 123
AND a.id = b.id'
FROM information_schema.columns
WHERE table_name = 'a' -- table name, case sensitive
AND table_schema = 'public' -- schema name, case sensitive
AND column_name <> 'id' -- all columns except id
);
END
$do$;
假设中b
的每个列都有一个匹配的列a
,但并非相反。b
可以有其他列。
WHERE b.id = 123
是可选的,以更新选定的行。
SQL提琴。
相关答案以及更多说明:
使用纯SQL的部分解决方案
带有共享列的列表
您仍然需要知道两个表共享的列名列表。具有用于更新多列的语法快捷方式-短于到目前为止在任何情况下建议的答案。
UPDATE b
SET ( column1, column2, column3)
= (a.column1, a.column2, a.column3)
FROM a
WHERE b.id = 123 -- optional, to update only selected row
AND a.id = b.id;
SQL提琴。
在问这个问题很久之前,Postgres 8.2就在2006年引入了此语法。手册中的详细信息。
有关:
带有列列表 B
如果A
定义了NOT NULL
(但不一定是B
)的所有列,
并且您知道B
(但不一定是A
)的列名。
UPDATE b
SET (column1, column2, column3, column4)
= (COALESCE(ab.column1, b.column1)
, COALESCE(ab.column2, b.column2)
, COALESCE(ab.column3, b.column3)
, COALESCE(ab.column4, b.column4)
)
FROM (
SELECT *
FROM a
NATURAL LEFT JOIN b -- append missing columns
WHERE b.id IS NULL -- only if anything actually changes
AND a.id = 123 -- optional, to update only selected row
) ab
WHERE b.id = ab.id;
该NATURAL LEFT JOIN
联接从行b
,其中同名的所有列持有相同的价值观。在这种情况下,我们不需要更新(没有任何变化),并且可以在流程的早期删除这些行(WHERE b.id IS NULL
)。
我们仍然需要找到匹配的行,因此b.id = ab.id
在外部查询中。
db <> fiddle here
旧的sqlfiddle。
这是除了FROM
子句之外的标准SQL 。
无论实际存在的列是什么,它都可以工作A
,但是查询无法区分实际的NULL值和其中的缺失列A
,因此只有A
定义了其中的所有列,这才是可靠的NOT NULL
。
根据您对两个表的了解,可能有多种变体。