Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using return value from DELETE for UPDATE in Postgres

I need to update a table using a value deleted from another table. The situation is a comment vote scorekeeper similar to the one on SO. I'm using python to work the postgres, but that shouldn't make a difference.

query="""
UPDATE comment SET score=score-(DELETE FROM history
                                WHERE commentId=%(commentId)s AND
                                      userIdentity=%(userIdentity)s RETURNING vote)
WHERE commentId=%(commentId)s;
"""
cursor.execute(query, data)

The error arises at (DELETE FROM; a syntax error arises. I can replace the DELETE statement with a SELECT statement and it will work, is there something I am missing here? I want to use the returning value in an update. Is this possible? Anything helps.

Relevent schema:

CREATE TABLE history (
    commentId bigint,
    vote int,
    userIdentity varchar(256),
);
CREATE TABLE comment (
    id bigint,
    score bigint,
);

history.vote is normally 1 or -1.

like image 803
JDong Avatar asked Aug 01 '13 14:08

JDong


People also ask

Does delete return any value SQL?

The standard DELETE statement in SQL returns the number of deleted rows. In PostgreSQL you can make DELETE statement return something else. You can return all rows that have been deleted. You can return the columns of your choice.

What is returning * Postgres?

A common shorthand is RETURNING * , which selects all columns of the target table in order. In an INSERT , the data available to RETURNING is the row as it was inserted. This is not so useful in trivial inserts, since it would just repeat the data provided by the client.

What does delete return in SQL?

Single-Table Syntax. The DELETE statement deletes rows from tbl_name and returns the number of deleted rows.

What does insert query return in Postgres?

The optional RETURNING clause causes INSERT to compute and return value(s) based on each row actually inserted (or updated, if an ON CONFLICT DO UPDATE clause was used). This is primarily useful for obtaining values that were supplied by defaults, such as a serial sequence number.


1 Answers

PostgreSQL doesn't allow mix UPDATE and DELETE statements as subquery.

You can use a little bit different strategy - updateable CTE

postgres=# WITH t1 AS (DELETE FROM foo RETURNING *), 
                t2 AS (INSERT INTO deleted 
                          SELECT * FROM t1 RETURNING *) 
             SELECT max(a) FROM t2;

so

postgres=# CREATE TABLE comment(id int, score int);
CREATE TABLE
postgres=# CREATE TABLE history(id int, comment_id int, vote int);
CREATE TABLE
postgres=# INSERT INTO comment values(1,10);
INSERT 0 1
postgres=# INSERT INTO comment values(2,20);
INSERT 0 1
postgres=# INSERT INTO history values(1,1,5);
INSERT 0 1
postgres=# WITH t1 AS (DELETE FROM history 
                       WHERE id=1 
                       RETURNING comment_id, vote) 
           UPDATE comment SET score=score-t1.vote 
           FROM t1 
           WHERE t1.comment_id=comment.id;
UPDATE 1
postgres=# select * from comment;
 id | score 
----+-------
  2 |    20
  1 |     5
(2 rows)

Attention: It require 9.1 or newer

like image 57
Pavel Stehule Avatar answered Sep 26 '22 01:09

Pavel Stehule