Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SQL CTE Syntax to DELETE / INSERT rows

What's the CTE syntax to delete from a table, then insert to the same table and return the values of the insert?

Operating on 2 hours of sleep and something doesn't look right (besides the fact that this won't execute):

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 *
)

The expected behavior is to first clear all the records for an ID, then insert records for the same ID (intentionally not an upsert) and return those inserted records (not the deletions).

like image 943
vol7ron Avatar asked Jun 17 '15 21:06

vol7ron


People also ask

Can you delete rows from CTE?

Deleting from a CTE is not possible.

Can we use CTE with insert statement?

A CTE must be followed by a single SELECT , INSERT , UPDATE , or DELETE statement that references some or all the CTE columns. A CTE can also be specified in a CREATE VIEW statement as part of the defining SELECT statement of the view.

Can we use delete with CTE in Oracle?

In Oracle neither the CTE nor the INNER JOIN are valid for the DELETE command. The same applies for the INSERT and UPDATE commands. You can also delete from the results of a subquery.

Can we perform DML on CTE?

CTE can be used for both selects and DML (Insert, Update, and Delete) statements.


1 Answers

Your question update made clear that you cannot do this in a single statement.

Packed into CTEs of the same statement, both operations (INSERT and DELETE) would see the same snapshot of the table and execute virtually at the same time. I.e., the INSERT would still see all rows that you thought to be deleted already. The manual:

All the statements are executed with the same snapshot (see Chapter 13), so they cannot "see" one another's effects on the target tables.

You can wrap them as two independent statements into the same transaction - which doesn't seem strictly necessary either, but it would allow the whole operation to succeed / fail atomically:

BEGIN;

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

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

COMMIT;

Now, the INSERT can see the results of the DELETE.

like image 65
Erwin Brandstetter Avatar answered Oct 02 '22 21:10

Erwin Brandstetter