我设法从我的129,000行生产数据库(Heroku上的Postgres 9.4)中的表中删除了4,000行,但仅在几天后才发现问题。
我在丢失之前有一个备份,但只想有选择地将丢失的行恢复到表中,保留他们的id。 (完全恢复不是一个选项,因为新数据已添加到表中。)
在本地测试数据库中,我已将备份表导入为articles_backup
,并与实际的articles
表一起导入。我想查找articles_backups
中articles
中缺少的所有行,然后将这些行复制到新表articles_restores
,然后我将恢复到生产数据库,返回articles
1}} table(保留记录id)。
此查询成功返回已删除记录的所有ID:
select articles_backups.id
from articles_backups
left outer join articles on (articles_backups.id = articles.id)
where articles.id is null
但是我无法将结果复制到新表中。我没有成功尝试过:
select *
into articles_restores
from articles_backups
left outer join articles on (articles_backups.id = articles.id)
where articles.id is null;
给出了:
ERROR: column "id" specified more than once
答案 0 :(得分:2)
基本上,您使用LEFT JOIN
/ IS NULL
的查询可以满足您的要求:
您收到错误是因为您从两个表中选择了所有列,并且两者都有id
列。无法创建具有重复列名的新表,并且它不是您想要的开头。仅从articles_backups
中选择列:
CREATE TABLE articles_restores AS
SELECT ab.*
FROM articles_backups ab
LEFT JOIN articles a USING (id)
WHERE a.id IS NULL;
在阅读时,我使用表别名简化了查询语法。 USING
子句只是为了方便更短的代码。它将两个id
列折叠成一个,但如果SELECT *
,则所有其他列仍然在那里两次。
使用CREATE TABLE AS
。 也由SQL标准定义并在Postgres中实现,但不鼓励使用它。它在PL / pgSQL函数中用于不同的目的。详细说明:SELECT INTO
答案 1 :(得分:1)
您可以使用except检索articles_backup
中与articles
不同的所有行:
(假设两个表在相同的顺序中具有相同的列)
你也可以create a temp table使用这些信息来简化你的修复陈述:
create table temp_articles as
select * from articles_backup
except
select * from articles
第1步 - 更新articles
中“articles_backup”中的行。
此步骤需要注意......您必须建立规则,以便在articles
中存在的数据与temp_articles
中存在的数据之间进行选择。
UPDATE articles a
SET a.col1=b.col1,
a.col2=b.col2,
(... other columns ...)
FROM (SELECT * FROM temp_articles) AS b
WHERE a.id = b.id and /* your rule for data to be (or not) updated goes here */
第2步 - 插入articles
中不存在的'articles_backup'中的行(您删除的记录):
insert into articles
select * from temp_articles where id not in (select id from articles)
如果您需要更多帮助,请告诉我们。