Как я могу вставить возврат DELETE в INSERT в postgresql? - PullRequest
17 голосов
/ 05 июля 2011

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

insert into b (one,two,num) values delete from a where id = 1 returning one, two, 5;

При запуске я получаю следующую ошибку:

ОШИБКА: синтаксическая ошибка на или около "delete"

Кто-нибудь может указать, как это сделать, или есть лучший способ?или это невозможно?

Ответы [ 5 ]

43 голосов
/ 05 июля 2011

Вы не можете сделать это до PostgreSQL 9.1, который еще не выпущен.И тогда синтаксис будет

WITH foo AS (DELETE FROM a WHERE id = 1 RETURNING one, two, 5)
    INSERT INTO b (one, two, num) SELECT * FROM foo;
5 голосов
/ 05 июля 2011

До PostgreSQL 9.1 вы можете создать такую ​​изменчивую функцию, как эта (не проверено) :

create function move_from_a_to_b(_id integer, _num integer)
returns void language plpgsql volatile as
$$
  declare
    _one integer;
    _two integer;
  begin
    delete from a where id = _id returning one, two into strict _one, _two;
    insert into b (one,two,num) values (_one, _two, _num);
  end;
$$

А затем просто используйте select move_from_a_to_b(1, 5).Функция имеет преимущество перед двумя операторами в том, что она всегда будет выполняться в одной транзакции - нет необходимости явно запускать и фиксировать транзакцию в клиентском коде.

1 голос
/ 23 июля 2013

Для всех версий PostgreSQL вы можете создать триггерную функцию для удаления строк из таблицы и вставки их в другую таблицу. Но это кажется медленнее, чем массовая вставка, выпущенная в PostgreSQL 9.1. Вам просто нужно переместить старые данные в другую таблицу, прежде чем они будут удалены. Это делается с типом данных OLD:

CREATE FUNCTION moveDeleted() RETURNS trigger AS $$
    BEGIN
        INSERT INTO another_table VALUES(OLD.column1, OLD.column2,...);
        RETURN OLD;
    END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER moveDeleted
BEFORE DELETE ON table 
    FOR EACH ROW
        EXECUTE PROCEDURE moveDeleted();

Как и в предыдущем ответе, после PostgreSQL 9.1 вы можете сделать это:

WITH tmp AS (DELETE FROM table RETURNING column1, column2, ...)
    INSERT INTO another_table (column1, column2, ...) SELECT * FROM tmp;
0 голосов
/ 05 июля 2011

Как «AI W», два оператора, безусловно, являются лучшим вариантом для вас, но вы также можете подумать о написании триггера для этого. Каждый раз, когда что-то удаляется в вашей первой таблице, другое заполняется.

0 голосов
/ 05 июля 2011

Тот синтаксис, который у вас есть, недействителен. 2 заявления - лучший способ сделать это. Наиболее интуитивно понятный способ сделать это - сначала вставить, а потом удалить.

...