一个表的SQL更新字段来自另一个表的字段

时间:2010-05-04 08:27:15

标签: sql postgresql sql-update dynamic-sql

我有两张桌子:

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

A将永远是B的子集(意味着A的所有列也在B)。

我想更新ID中包含B的特定A的记录,其A的所有列都包含ID的数据。此A存在BUPDATE

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

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

7 个答案:

答案 0 :(得分:197)

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

UPDATE b
SET column1 = a.column1,
  column2 = a.column2,
  column3 = a.column3
FROM a
WHERE a.id = b.id
AND b.id = 1

答案 1 :(得分:40)

问题已经过去了,但我觉得还没有给出最好的答案。

  

是否有UPDATE语法... 而未指定列名

使用动态SQL的常规解决方案

除了要加入的一些唯一列(示例中的 id )之外,您不需要知道任何列名称。对于我能想到的任何可能的角落情况都可靠地工作。

这是PostgreSQL特有的。我正在构建基于information_schema的动态代码,特别是表information_schema.columns,它在ANSI SQL中定义,大多数现代RDBMS(Oracle除外)都支持它。但是执行动态SQL的DO代码的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 Fiddle.

相关答案以及更多解释:

使用纯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 Fiddle.

这个语法是在2006年12月的Postgres 8.2中引入的,早在提出问题之前 更多细节in the manual以及关于dba.SE的相关答案:

使用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

SQL Fiddle.

这是标准的SQL except for the FROM clause 无论A中实际存在哪些列,它都可以工作,但查询无法区分A中的实际NULL值和缺少的列,因此只有A中的所有列才可靠定义NOT NULL

根据您知道关于两个表的内容,有多种可能的变体。

答案 2 :(得分:22)

我已经使用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中不支持FROM原因,也不支持ANSI SQL。

它适用于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)

答案 3 :(得分:7)

这是一个很好的帮助。代码

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

让它发挥作用。

答案 4 :(得分:5)

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

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

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

这样就无需更新B.

但请务必阅读所有details

否则,你要求的东西不被认为是一种好习惯 - 不鼓励用SELECT * ...的观点等动态的东西(因为这样的轻微便利可能会破坏更多的东西而不是帮助的东西),你要求的是等效于UPDATE ... SET命令。

答案 5 :(得分:0)

你可以构建和执行动态sql来做到这一点,但它真的不理想

答案 6 :(得分:-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