【问题标题】:How do I switch two ID [PK] on postgres database?如何在 postgres 数据库上切换两个 ID [PK]?
【发布时间】:2012-04-19 06:10:32
【问题描述】:

我想更改 Postgres 上两行的 ID,以切换它们。它们已经被定义为外键,所以我不能使用第三个数字来进行切换。

如何在一个 SQL 查询或事务中执行此操作?

例子:

UPDATE mytable SET id=2 WHERE ID=1;
UPDATE mytable SET id=1 WHERE ID=2

【问题讨论】:

  • 当您拥有事务完整性时,您不需要在一行中完成!!
  • 你是说修改后id=1的记录需要保持id=1的链接吗?即你不想改变依赖表?
  • 除了更改 ID 之外,您可以使用更改所有其他属性的解决方案吗?
  • this question密切相关。
  • 交换内容而不是交换标识符怎么样?

标签: sql postgresql


【解决方案1】:

您提到了外键,但尚不清楚id 是外键约束的引用列还是引用列。

如果 id 是引用列,您只需定义 fk 约束 ON UPDATE CASCADE。然后您可以随意更改您的id。更改会级联到依赖列。


如果 id 是引用列(并且没有其他外键约束指向它),那么自 PostgreSQL 9.0 以来还有另一种更快的方法。您可以使用可延迟的主键或唯一键。考虑以下演示:

注意,如果您想使用另一个表中的 外键 约束来引用 id,则不能使用此功能。我引用手册here

引用的列必须是不可延迟的唯一列 或引用表中的主键约束。

测试平台:

CREATE TEMP TABLE t
( id integer
 ,txt text
 ,CONSTRAINT t_pkey PRIMARY KEY (id) DEFERRABLE INITIALLY DEFERRED
);
INSERT INTO t VALUES
 (1, 'one')
,(2, 'two');

更新:

UPDATE t
SET    id = t_old.id
FROM   t t_old
WHERE (t.id, t_old.id) IN ((1,2), (2,1));

结果:

SELECT * FROM t; 

id | txt
---+-----
2  | one
1  | two

您还可以在同一事务中声明约束DEFERRABLE INITIALLY IMMEDIATE 并使用SET CONSTRAINTS ... DEFERRED

请务必阅读手册中的详细信息:


甚至似乎可以使用 DEFERRABLE INITIALLY IMMEDIATE 而不是 SET CONSTRAINTS。我发了question about that

【讨论】:

  • 我了解引用的列不能是可延迟主键的列。还是我错了?
  • 正如我之前在已删除的答案中评论的那样,这是行不通的,因为从最新的 PG9.1 开始,您不能有 FOREIGN KEY 指向具有 DEFERRABLE 约束的唯一列,并且问题特别提到了FK的存在。
  • @Clodoaldo:是的,这是关于外键的一个重要限制。我在答案中添加了注释..
  • @DanielVérité:从问题中不清楚id 是外键约束的引用列还是引用列。如果它是引用列,这将起作用。
  • @Erwin:我在阅读问题时也想知道,但由于标题显示“...ID [PK]...”,我认为 mytable.ID 是主键,还有一些未提及表指向它。也许作者应该澄清一下。
【解决方案2】:
begin;
alter table mytable drop constraint_name;
UPDATE mytable SET id=-1 WHERE ID=1;
UPDATE mytable SET id=1 WHERE ID=2;
UPDATE mytable SET id=2 WHERE ID=-1;
alter table mytable add table_constraint;
commit;

【讨论】:

  • +1 为简单起见,但仅在应用更改一次的情况下...不适合在任何修改数据的语句之后运行每日脚本
【解决方案3】:

您是否尝试过类似的方法:

BEGIN;

CREATE TEMP TABLE updates ON COMMIT DROP AS
SELECT column1::int oldid, column2::int newid
FROM ( VALUES (1, 2), (2, 1) ) foo;

UPDATE mytable
FROM updates
SET id = newid
WHERE id = oldid;

--COMMIT;
ROLLBACK;

当然,当您准备好时,回滚会被注释掉并提交。

【讨论】:

  • 你肯定错过了UPDATE上的一些东西。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-01-15
  • 1970-01-01
  • 2017-10-29
  • 2022-12-28
  • 2021-04-20
  • 2011-04-26
相关资源
最近更新 更多