我有两张桌子:
A [ID, column1, column2, column3]
B [ID, column1, column2, column3, column4]
A
将永远是B
的子集(意味着A
的所有列也在B
)。
我想更新ID
中包含B
的特定A
的记录,其A
的所有列都包含ID
的数据。此A
存在B
和UPDATE
。
是否有{{1}}语法或其他任何方法可以在不指定列名的情况下执行此操作,只是说“设置A的所有列?
我正在使用PostgreSQL,因此也接受了一个特定的非标准命令(但不是首选)。
答案 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语法... 而未指定列名?
除了要加入的一些唯一列(示例中的 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
是可选的,仅更新选定的行。
相关答案以及更多解释:
您仍然需要知道两个表共享的列名列表。使用语法快捷方式更新多个列 - 比任何情况下到目前为止建议的其他答案都短。
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;
这个语法是在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 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