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

Nir*_*Nir 115 sql postgresql dynamic-sql sql-update

我有两张桌子:

A [ID, column1, column2, column3]
B [ID, column1, column2, column3, column4]
Run Code Online (Sandbox Code Playgroud)

A将永远是其子集B(意味着所有列A也在其中B).

我想更新具有特定ID输入的记录,其中B包含来自A所有列的数据A.这ID存在于AB.

是否有UPDATE语法或任何其他方法来指定列名称,只是说"设置A的所有列"

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

Sco*_*ley 216

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

UPDATE b
SET column1 = a.column1,
  column2 = a.column2,
  column3 = a.column3
FROM a
WHERE a.id = b.id
AND b.id = 1
Run Code Online (Sandbox Code Playgroud)

  • 问题是询问如何做*没有*指定所有列名称.(我也是.) (9认同)
  • @YasirAzgar b.id = 1 是限制 b 中更新的行。否则我们将更新表中的每一行。有时,这可能就是您想要的。但最初的问题是更新 b 中的特定行。 (5认同)
  • 我同意@cluesque,但这个答案是一种很好的方法,可以将表中一列中的值用作查找表,以替换另一个表中列中的值(参见[SO 21657475](https://stackoverflow.com/)问题/ 21657475/update-one-field-from-another-table/50239731#50239731)),所以+1 ...... (2认同)
  • 为什么需要 b.id = 1 ? (2认同)
  • 这就是我解决特定问题所需的:使用另一个表的不同名称列中的值更新一个表的列。 (2认同)

Erw*_*ter 44

这个问题已经过时了,但我觉得还没有给出最好的答案.

是否有UPDATE语法... 没有指定列名

动态SQL的一般解决方案

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

这是PostgreSQL特有的.我正在构建基于information_schema的动态代码,特别id是在ANSI SQL中定义的表,而大多数现代RDBMS(Oracle除外)都支持它.但是PL/pgSQL代码执行动态SQL 的information_schema.columns声明完全是非标准的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$;
Run Code Online (Sandbox Code Playgroud)

假设在一个匹配列DO每一b,而不是倒过来.a可以有其他列.

b 是可选的,仅更新选定的行.

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;
Run Code Online (Sandbox Code Playgroud)

SQL小提琴.

这个语法是在2006年12月的Postgres 8.2中引入的,早在提出问题之前.
有关dba.SE 手册和相关答案的更多详细信息:

包含列中的列 WHERE b.id = 123

如果B定义了所有列A(但不一定NOT NULL),
并且知道列名B(但不一定B).

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;
Run Code Online (Sandbox Code Playgroud)

A联接从行NATURAL LEFT JOIN,其中同名的所有列持有相同的价值观.在这种情况下我们不需要更新(没有任何更改),并且可以在流程早期消除这些行(b).
我们仍然需要找到匹配的行,所以WHERE b.id IS NULL在外部查询中.

SQL小提琴.

这是标准SQL,除了该b.id = ab.id子句.
无论哪个列实际存在FROM,它都可以工作,但查询无法区分实际的NULL值和缺少的列A,因此只有在A定义了所有列时才可靠A.

根据您对两个表的了解,有多种可能的变化.


joc*_*han 23

我已经使用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
Run Code Online (Sandbox Code Playgroud)

注意:主要问题是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)
Run Code Online (Sandbox Code Playgroud)

最后!它适用于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)
Run Code Online (Sandbox Code Playgroud)

  • 请注意,第二个和第三个查询并不完全等同于第一个查询.如果在`B`中找不到匹配的行,则第一个语句**nothing*(原始行保持不变),而其他两个用NULL值覆盖列. (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;
Run Code Online (Sandbox Code Playgroud)

工作得很好.

注意到你需要一个括号""

From "tbl_a" a
Run Code Online (Sandbox Code Playgroud)

使它工作.


Unr*_*son 5

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

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

CREATE TABLE B (
    column4       text
) INHERITS (A);
Run Code Online (Sandbox Code Playgroud)

这避免了更新B的需要.

但一定要阅读所有细节.

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

  • 是的,如果只是在某些情况下,那么继承将不起作用,在这种情况下,我建议不要使用动态查询方法.(仍然有方法可以使用postgres过程语言实现这一点.如果你想使用触发器也可以使用它们 - 通过添加同步字段,例如仅在设置时触发触发器). (2认同)

Dan*_*ink 0

您可以构建并执行动态 sql 来做到这一点,但这确实不理想