160

我有两张桌子:

A [ID, column1, column2, column3]
B [ID, column1, column2, column3, column4]

A将始终是的子集B(意味着 的所有列A也在 中B)。

我想用来自所有列的数据更新具有特定IDin的记录。这在和中都存在。BAAIDAB

是否有UPDATE语法或任何其他方法可以在不指定列名的情况下执行此操作,只需说“设置 A 的所有列”

我正在使用 PostgreSQL,因此也接受了特定的非标准命令(但是,不是首选)。

4

7 回答 7

299

您可以使用非标准的FROM子句。

UPDATE b
SET column1 = a.column1,
  column2 = a.column2,
  column3 = a.column3
FROM a
WHERE a.id = b.id
AND b.id = 1
于 2010-05-04T15:41:30.673 回答
61

这个问题很老,但我觉得还没有给出最好的答案。

是否有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

有多种可能的变化,这取决于您对这两个表的了解。

于 2014-04-25T03:46:18.517 回答
31

我已经使用 IBM DB2 数据库十多年了,现在正在尝试学习 PostgreSQL。

它适用于 PostgreSQL 9.3.4,但不适用于 DB2 10.5:

UPDATE B SET
     COLUMN1 = A.COLUMN1,
     COLUMN2 = A.COLUMN2,
     COLUMN3 = A.COLUMN3
FROM A
WHERE A.ID = B.ID

注意:主要问题是 DB2 和 ANSI SQL 不支持的 FROM 原因。

它适用于 DB2 10.5,但不适用于 PostgreSQL 9.3.4:

UPDATE B SET
    (COLUMN1, COLUMN2, COLUMN3) =
               (SELECT COLUMN1, COLUMN2, COLUMN3 FROM A WHERE ID = B.ID)

最后!它适用于 PostgreSQL 9.3.4 和 DB2 10.5:

UPDATE B SET
     COLUMN1 = (SELECT COLUMN1 FROM A WHERE ID = B.ID),
     COLUMN2 = (SELECT COLUMN2 FROM A WHERE ID = B.ID),
     COLUMN3 = (SELECT COLUMN3 FROM A WHERE ID = B.ID)
于 2014-11-26T12:41:42.350 回答
8

这是一个很大的帮助。编码

UPDATE tbl_b b
SET   (  column1,   column2,   column3)
    = (a.column1, a.column2, a.column3)
FROM   tbl_a a
WHERE  b.id = 1
AND    a.id = b.id;

完美运行。

注意到你需要一个括号“”

From "tbl_a" a

让它工作。

于 2014-05-16T18:56:32.663 回答
6

不一定是你问的,但也许使用 postgres 继承可能会有所帮助?

CREATE TABLE A (
    ID            int,
    column1       text,
    column2       text,
    column3       text
);

CREATE TABLE B (
    column4       text
) INHERITS (A);

这避免了更新 B 的需要。

但请务必阅读所有详细信息

否则,您所要求的不被认为是一种好的做法 -SELECT * ...不鼓励使用动态内容(例如视图)(因为这种轻微的便利可能会破坏更多的东西而不是帮助的东西),并且您所要求的内容将等同于UPDATE ... SET命令。

于 2010-05-04T08:48:10.177 回答
1

您可以构建和执行动态 sql 来执行此操作,但它确实不理想

于 2010-05-04T08:29:43.160 回答
-4

尝试关注

Update A a, B b, SET a.column1=b.column1 where b.id=1

已编辑:- 更新不止一列

Update A a, B b, SET a.column1=b.column1, a.column2=b.column2 where b.id=1
于 2010-05-04T08:33:07.613 回答