将一个 table 中缺失的记录复制到一个新的 table
Copy records missing from one table to a new table
我设法从我的 129,000 行生产数据库(Heroku 上的 Postgres 9.4)中的 table 中删除了 4,000 行,但几天后才发现问题。
我有丢失前的备份,但只想选择性地将丢失的行恢复到table,保留它们的 ID。 (完全恢复不是一个选项,因为新数据已经添加到 table。)
我将备份的 table 作为 articles_backup
与实际的 articles
table 一起导入到本地测试数据库中。我想在 articles_backups
中找到 articles
中丢失的所有行,然后将它们复制到新的 table articles_restores
中,然后我将恢复到生产数据库,返回进入 articles
table(保留记录 ID)。
查询成功returns所有删除记录的id:
select articles_backups.id
from articles_backups
left outer join articles on (articles_backups.id = articles.id)
where articles.id is null
但我无法将结果复制到新的 table。我试过没有成功:
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
您可以使用 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_backup' 中不存在于 articles
中的行(您已删除的记录):
insert into articles
select * from temp_articles where id not in (select id from articles)
如果您需要更多帮助,请告诉我们。
基本上,您使用 LEFT JOIN
/ IS NULL
的查询会满足您的要求:
- Select rows which are not present in other table
您收到错误是因为您 select 来自两个 table 的所有列,并且两者中都有一个 id
列。无法创建具有重复列名的新 table,这不是您想要的开头。只有 select 列来自 articles_backups
:
CREATE TABLE articles_restores AS
SELECT <b>ab.*</b>
FROM articles_backups ab
LEFT JOIN articles a USING (id)
WHERE a.id IS NULL;
我使用 table 别名简化了您的查询语法。 USING
子句只是为了方便缩短代码。它将两个 id
列折叠成一个,但如果您 SELECT *
.
所有其他列仍然在那里两次
使用CREATE TABLE AS
。 SELECT INTO
也由 SQL 标准定义并在 Postgres 中实现,但不鼓励使用它。它在 PL/pgSQL 函数中用于不同的目的。详情:
- Creating temporary tables in SQL
我设法从我的 129,000 行生产数据库(Heroku 上的 Postgres 9.4)中的 table 中删除了 4,000 行,但几天后才发现问题。
我有丢失前的备份,但只想选择性地将丢失的行恢复到table,保留它们的 ID。 (完全恢复不是一个选项,因为新数据已经添加到 table。)
我将备份的 table 作为 articles_backup
与实际的 articles
table 一起导入到本地测试数据库中。我想在 articles_backups
中找到 articles
中丢失的所有行,然后将它们复制到新的 table articles_restores
中,然后我将恢复到生产数据库,返回进入 articles
table(保留记录 ID)。
查询成功returns所有删除记录的id:
select articles_backups.id
from articles_backups
left outer join articles on (articles_backups.id = articles.id)
where articles.id is null
但我无法将结果复制到新的 table。我试过没有成功:
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
您可以使用 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_backup' 中不存在于 articles
中的行(您已删除的记录):
insert into articles
select * from temp_articles where id not in (select id from articles)
如果您需要更多帮助,请告诉我们。
基本上,您使用 LEFT JOIN
/ IS NULL
的查询会满足您的要求:
- Select rows which are not present in other table
您收到错误是因为您 select 来自两个 table 的所有列,并且两者中都有一个 id
列。无法创建具有重复列名的新 table,这不是您想要的开头。只有 select 列来自 articles_backups
:
CREATE TABLE articles_restores AS
SELECT <b>ab.*</b>
FROM articles_backups ab
LEFT JOIN articles a USING (id)
WHERE a.id IS NULL;
我使用 table 别名简化了您的查询语法。 USING
子句只是为了方便缩短代码。它将两个 id
列折叠成一个,但如果您 SELECT *
.
使用CREATE TABLE AS
。 也由 SQL 标准定义并在 Postgres 中实现,但不鼓励使用它。它在 PL/pgSQL 函数中用于不同的目的。详情:SELECT INTO
- Creating temporary tables in SQL