将一个表中缺少的记录复制到新表中

时间:2015-09-03 02:53:22

标签: sql ruby-on-rails postgresql heroku left-join

我设法从我的129,000行生产数据库(Heroku上的Postgres 9.4)中的表中删除了4,000行,但仅在几天后才发现问题。

我在丢失之前有一个备份,但只想有选择地将丢失的行恢复到表中,保留他们的id。 (完全恢复不是一个选项,因为新数据已添加到表中。)

在本地测试数据库中,我已将备份表导入为articles_backup,并与实际的articles表一起导入。我想查找articles_backupsarticles中缺少的所有行,然后将这些行复制到新表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

2 个答案:

答案 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 SELECT INTO 也由SQL标准定义并在Postgres中实现,但不鼓励使用它。它在PL / pgSQL函数中用于不同的目的。详细说明:

答案 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)

如果您需要更多帮助,请告诉我们。