Как переключить два ID [PK] в базу данных postgres?

Я хочу изменить идентификатор в двух строках на Postgres, чтобы переключить их. Они уже определены как внешний ключ, поэтому я не могу использовать третий номер для переключения.

Как это сделать в одном SQL-запросе или транзакции?

Пример:

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

Ответ 1

Вы указываете внешние ключи, но остается неясным, является ли id ссылочным или ссылочным столбцом ограничения внешнего ключа.

Если id является ссылочным столбцом, вы просто определяете ограничение fk ON UPDATE CASCADE. Затем вы можете изменить id столько, сколько хотите. Изменения каскадируются в зависимости от столбцов.


Если id является ссылочным столбцом (никакие другие ограничения внешнего ключа не указывают на него), то есть другой, более быстрый способ с PostgreSQL 9.0. Вы можете использовать отложенный первичный или уникальный ключ. Рассмотрим следующую демонстрацию:

Примечание, которую вы не можете использовать, если вы хотите ссылаться на id с ограничением внешнего ключа из другой таблицы. Я цитирую руководство здесь:

Указанные столбцы должны быть столбцами неотделяемой уникальной или ограничение первичного ключа в ссылочной таблице.

Testbed:

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:

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 и no SET CONSTRAINTS. Я отправил вопрос об этом.

Ответ 2

Вы пробовали что-то вроде:

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;

Конечно, откат закомментирован и фиксируется, когда вы готовы к работе.

Ответ 3

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;