2

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

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

例子:

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

3 回答 3

5

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

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


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

请注意id,如果您想使用来自另一个表的外键约束进行引用,则不能使用它。我在这里引用手册:

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

试验台:

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

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


Even 似乎可以使用DEFERRABLE INITIALLY IMMEDIATE并且没有SET CONSTRAINTS. 我发布了一个关于那个的问题。

于 2012-04-05T16:04:26.357 回答
1

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

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;

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

于 2012-04-05T14:19:16.843 回答
1
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;
于 2012-04-05T13:54:40.120 回答