2015-06-17 3 views
2

Что синтаксис CTE для удалить из таблицы, а затем вставить в ту же таблицу и возвращать значения из вставки?SQL КТР Синтаксис для DELETE/INSERT строки

Работая на 2 часа сна и что-то не выглядит правильно (кроме того, что это не будет исполнять):

WITH delete_rows AS (
    DELETE FROM <some_table> WHERE id = <id_value> 
    RETURNING * 
) 
SELECT * FROM delete_rows 
UNION 
(
    INSERT INTO <some_table> (id, text_field) 
     VALUES (<id_value>, '<text_field_value>') 
     RETURNING * 
) 

Ожидаемое поведение является в первую очистить все записи для идентификатора, затем вставьте записи для того же ID (намеренно не upsert) и верните те вставленные записи (а не удаления).

+1

Вставка и удаление не подключены, но вы хотите вернуть все строки из * обеих * операций? –

+0

@ErwinBrandstetter действительно может не заботиться о * delete *, но не был уверен, что это хороший синтаксис, будет иметь дело с этим после того, как я смогу выполнить операции в порядке – vol7ron

+0

Ну, этот последний бит может быть проблемой. Пожалуйста, уточните свой вопрос, определяющий, как * точно * вы ожидаете, что оба будут выполнены «в порядке». –

ответ

4

В вашем обновлении вопроса ясно, что вы не можете сделать это в одном заявлении.

Упакованный в КТР того же заявления, как операции (INSERT и DELETE) будет видеть один и тот же снимок таблицы и выполнить практически одновременно. I.e., INSERT все равно будут видеть все строки, которые, по вашему мнению, уже были удалены. Per documentation:

Все инструкции выполняются с тем же снимок (см главу 13), так что они не могут «видеть» друг друга воздействие на целевые таблицы.

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

BEGIN; 

DELETE FROM <some_table> WHERE id = <id_value>; 

INSERT INTO <some_table> (id, text_field) 
VALUES (<id_value>, '<text_field_value>') 
RETURNING *; 

COMMIT; 

Теперь, INSERT видны результаты DELETE.

+0

Не 'union' обеспечивают некоторую синхронность? – vol7ron

+1

@ vol7ron: Ну, 'UNION' оценивает слева направо (см. Последнюю главу здесь: http://stackoverflow.com/a/30813090/939860). Вы также можете ссылаться на то, что вы получаете из предложения 'RETURNING' в следующем CTE, чтобы заставить порядок оценки. Но CTE *** всегда *** видят тот же снимок базовых таблиц. –

+0

Итак, может существовать условие гонки с другим запросом, нет резервирования на уровне таблиц или ограничений, но внутри запроса он будет действовать последовательно, как ожидалось, правильно? Просто хочу удостовериться, что хотя он оставлен вправо, что он не работает параллельно или прыгает вперед, пока не завершится одна операция. – vol7ron

0
CREATE TABLE test_table (value TEXT UNIQUE); 
INSERT INTO test_table SELECT 'value 1'; 
INSERT INTO test_table SELECT 'value 2'; 

WITH delete_row AS (DELETE FROM test_table WHERE value='value 2' RETURNING 0) 
    INSERT INTO test_table 
    SELECT DISTINCT 'value 2' 
    FROM (SELECT 'dummy') dummy 
    LEFT OUTER JOIN delete_row ON TRUE 
    RETURNING *; 

Вышеупомянутый запрос обрабатывает ситуации, когда DELETE удаляет 0/1/несколько строк.

Смежные вопросы