【问题标题】:Copy records missing from one table to a new table将一张表中缺失的记录复制到新表中
【发布时间】:2015-09-03 02:53:21
【问题描述】:

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

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

在本地测试数据库中,我已将备份表导入为articles_backup,以及实际的articles 表。我想在articles_backups 中找到articles 中缺少的所有行,然后将它们复制到一个新表articles_restores,然后我将恢复到生产数据库,回到articles 表中(保留记录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

【问题讨论】:

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


    【解决方案1】:

    基本上,您使用 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 ASSELECT INTO 也是由 SQL 标准定义并在 Postgres 中实现,但不鼓励使用它。它在 PL/pgSQL 函数中用于不同的目的。详情:

    【讨论】:

    • 谢谢欧文。那里也有很好的参考。
    【解决方案2】:

    您可以使用exceptarticles_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)
    

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

    【讨论】:

    • 感谢 Fabio / 那里提供了很棒的信息,这使我能够通过一些调整来恢复丢失的表。
    猜你喜欢
    • 2019-10-22
    • 1970-01-01
    • 1970-01-01
    • 2021-05-05
    • 2014-08-09
    • 1970-01-01
    • 2021-12-16
    • 1970-01-01
    • 2017-08-23
    相关资源
    最近更新 更多