我有两张表(例如' foo'和' bar'),结构相同,主键(例如' a'):
CREATE TABLE foo(a INT PRIMARY KEY, b VARCHAR(10));
INSERT INTO foo(a, b) VALUES (1, 'foo'), (2, 'foo');
CREATE TABLE bar(a INT PRIMARY KEY, b VARCHAR(10));
INSERT INTO bar(a, b) VALUES (2, 'bar'), (3, 'bar');
现在我想更新表格的行' foo'使用表格中的行值' bar'主键匹配的位置,我想插入表中的行' bar'进入表格#foo'如果主要密钥在表格中已经不存在,那就是:
UPDATE foo SET b = bar.b FROM bar WHERE foo.a = bar.a;
INSERT INTO foo SELECT bar.* FROM bar LEFT JOIN foo USING (a) WHERE foo.a IS NULL;
这就是我想要的,但我想知道是否有更有效的方法来做到这一点?
答案 0 :(得分:1)
如果其他人不同时访问您的表,您可以使用FULL [OUTER] JOIN
查询创建一个新的合并表,其中bar的值优先。
如果你有并发访问权限,但能够锁定这两个表,那也是有效的:
BEGIN;
LOCK foo, bar; -- if you need it
CREATE TABLE baz AS
SELECT a, COALESCE(b.b, a.b) AS b -- bar gets priority
FROM foo f
FULL JOIN bar b USING (a)
ORDER BY a; -- optional order by
-- you need table name foo?
DROP TABLE foo, bar;
ALTER TABLE baz RENAME TO foo;
ALTER TABLE foo ADD CONSTRAINT foo_a_pkey PRIMARY KEY (a);
-- do more?
COMMIT;
如果你有大量的重叠,那么编写一个没有死行的新的原始(集群)表比更新大部分旧表更有效。如果重叠不大,则更新/插入可能更有效。如果两个表都很小,请不要打扰并使用简单的解决方案。
新表显然没有旧表的任何索引或约束。重新创造你需要的东西。
如果你有很多依赖对象(视图,函数),你可能想要保留旧表。而是创建临时表TRUNCATE foo
并将数据写回到同一个表中。这也不会杀死等待现有表的并发事务。
BEGIN;
LOCK foo, bar; -- if you need it
SET temp_buffers = 500MB; -- if you need it
CREATE TEMP TABLE tmp AS
SELECT a, COALESCE(b.b, a.b) AS b -- bar gets priority
FROM foo f
FULL JOIN bar b USING (a);
-- for performance, you might want to drop indexes and constraints here ...
TRUNCATE foo;
INSERT INTO foo
SELECT * FROM tmp
ORDER BY a; -- optional
DROP TABLE bar; -- optional
-- ... and recreate previously dropped indexes and constraints here
COMMIT;
关于temp_buffers
:
并发写入会发生什么?