简体   繁体   中英

PostgreSQL and JDBC: Is `UPDATE table … RETURNING … INTO` supported?

I have a table with [primary key counters] for [per page comments in another table].
These primary keys are per page: for each page , comment IDs start on 1.

I'd like to atomically allocate 10 IDs to write 10 new comments.
— Can I do this with PostgreSQL and JDBC?

(And do you have any links to any example / the relevant JDBC documentation?)

I've found only examples about how returning the primary key of a newly inserted row, using some getGeneratedKeys which doesn't seem useful in my case.

***

I think the SQL UPDATE statement would look something like this:

update PAGES
set NEXT_COMMENT_ID = NEXT_COMMENT_ID + 10
where PAGE_ID = ?                    <-- next-comment-id is *per page*
returning NEXT_COMMENT_ID into ?

So, different threads and servers won't attempt to reuse/overwrite the same IDs (right?).

This is supported without using the execute() and getResult() methods on the Statement object:

Something like this (baring any error handling):

String sql = "update ... returning ...";
boolean hasResult = statement.execute(sql);
int affectedRows = 0;
ResultSet rs = null;
if (hasResult) {
  rs = statement.getResultSet();
}
int affectedRows = statement.getUpdateCount();

As you know what the statement does, this should be OK. Dealing with an "unknown" SQL statement is a bit more complicated because you need to call getMoreResults() and getUpdateCount() in a loop. See the Javadocs for details.

So you're wanting the following structure?:

x = page primary key y = comments primary key

Page Table

x
-
1
2
3
4 etc

Comments Table

x y
- -
1 1
1 2
1 3
1 4
2 1
2 2 
2 3
etc?

It would make most sense to have a foreign key structure here with an upper limit on the child records.

Creating a stored function that does update ... returning ... into works:

create or replace function INC_NEXT_PER_PAGE_REPLY_ID(
  site_id varchar(32), page_id varchar(32), step int) returns int as $$
declare
  next_id int;
begin
  update DW1_PAGES
    set NEXT_REPLY_ID = NEXT_REPLY_ID + step
    where SITE_ID = site_id and PAGE_ID = page_id
    returning NEXT_REPLY_ID into next_id;
  return next_id;
end;
$$ language plpgsql;

And calling it like so:

statement = connection.prepareCall(
    "{? = call INC_NEXT_PER_PAGE_REPLY_ID(?, ?, ?) }")
statement.registerOutParameter(1, java.sql.Types.INTEGER)
bind(values, statement, firstBindPos = 2)  // bind pos no. 1 is the return value
statement.execute()
nextNewReplyIdAfterwards = statement.getInt(1)

Related documentation:

To make the table contain a logical order then you may need to create a composite key and a foreign key within the child table.

sd=# create table x (x int);
CREATE TABLE
sd=# create table y (x int, y int);
CREATE TABLE

sd=# alter table x add primary key (x);
NOTICE:  ALTER TABLE / ADD PRIMARY KEY will create implicit index "x_pkey" for table "x"
ALTER TABLE
sd=# alter table y add foreign key (x) references x (x);
ALTER TABLE
sd=# alter table y add primary key (x,y);
NOTICE:  ALTER TABLE / ADD PRIMARY KEY will create implicit index "y_pkey" for table "y"
ALTER TABLE

sd=# insert into x values (1);
INSERT 0 1
sd=# insert into x values (2);
INSERT 0 1
sd=# insert into x values (3);
INSERT 0 1
sd=# insert into y values (1,1);
INSERT 0 1
sd=# insert into y values (1,2);
INSERT 0 1
sd=# insert into y values (1,3);
INSERT 0 1
sd=# insert into y values (1,1);
ERROR:  duplicate key value violates unique constraint "y_pkey" 
DETAIL:  Key (x, y)=(1, 1) already exists.

sd=# select * from x;
 x
---
 1
 2
 3
(3 rows)

sd=# select * from y;
 x | y
---+---
 1 | 1
 1 | 2
 1 | 3
(3 rows)

This should get you where you want to be?

You're doing an update but the statement generates results, so use executeQuery() instead of executeUpdate() . That's the real difference between the calls: executeQuery() deals with statements that yield a ResultSet ; while executeUpdate() returns count of the number of rows affected.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM