这个问题很老,但我觉得还没有给出最好的答案。
是否有UPDATE语法...而不指定列名?
使用动态 SQL 的通用解决方案
id除了要加入的一些唯一列(在示例中)之外,您不需要知道任何列名。对于我能想到的任何可能的极端情况都能可靠地工作。
这是 PostgreSQL 特有的。我正在基于information_schema构建动态代码,特别是 table information_schema.columns,它在 SQL 标准中定义,大多数主要的 RDBMS(Oracle 除外)都有它。但是带有执行动态 SQL 的PL/pgSQLDO代码的语句是完全非标准的 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是可选的,用于更新选定的行。
db<>fiddle here
旧sqlfiddle
更多解释的相关答案:
使用纯 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;
db<>fiddle here
旧sqlfiddle
这种语法是在 2006 年的 Postgres 8.2 中引入的,早在问这个问题之前。手册中的详细信息。
有关的:
包含列列表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了所有列时才可靠。ANOT NULL
有多种可能的变化,这取决于您对这两个表的了解。