Reputation: 25
i have this table below named roombooking:
I wrote this code that inserts a new row into roombooking(dont mind the details, just the hotelbookingID):
CREATE OR REPLACE FUNCTION my_function(startdate date , enddate date,idForHotel integer)
RETURNS void AS
$$
BEGIN
INSERT INTO roombooking("hotelbookingID","roomID","bookedforpersonID"
,checkin,checkout,rate)
SELECT rb."hotelbookingID", r."idRoom", p."idPerson"
,startdate-integer'20', startdate-integer'10', rr.rate
FROM(SELECT "hotelbookingID" FROM roombooking
WHERE "hotelbookingID"=
(select "hotelbookingID"
from roombooking
order by "hotelbookingID" desc
limit 1)+1) rb,
(SELECT "idRoom" FROM room
WHERE "idHotel"=idForHotel) r ,
(SELECT "idPerson" FROM person
ORDER BY random()
LIMIT 1) p,
(SELECT rate FROM roomrate
WHERE "idHotel"=idForHotel) rr;
END;
$$
LANGUAGE 'plpgsql';
The problem here is that i want to insert after the last row based on the last hotelbookingID(it is in asc order)
My function works but as i guess it cant find the last row ,in order to perform the insertion after . (I think that the problem can be spotted here :
SELECT "hotelbookingID" FROM roombooking
WHERE "hotelbookingID"=
(select "hotelbookingID"
from roombooking
order by "hotelbookingID" desc
limit 1)+1)
Any help would be valuable. Thank you.
Upvotes: 1
Views: 1013
Reputation: 247260
Any approach that uses a subquery to find the maximum existing id
is doomed to suffer from race conditions: if two such INSERT
s are running concurrently, they will end up with the same number.
Use an identity column:
ALTER TABLE roombooking
ALTER id ADD GENERATED ALWAYS AS IDENTITY (START 100000);
where 100000 is a value greater than the maximum id
in the table.
Then all you have to do is not insert anything into id
, and the column will be populated automatically.
Upvotes: 1
Reputation: 664980
That WHERE
condition makes no sense. There is no row in the roombooking
table whose id is 1 + the largest id in the roombooking
table.
You simply want to add 1 to the inserted value:
INSERT INTO roombooking("hotelbookingID", …)
SELECT rb."hotelbookingID" + 1, …
-- ^^^^
FROM (
SELECT "hotelbookingID"
FROM roombooking
ORDER BY "hotelbookingID" DESC
LIMIT 1
) rb,
…
That said, I would recommend to simply use a sequence instead (if you don't care about occasional gaps). If you really need a continuous numbering, I wouldn't use order by
+limit
though. Just use an aggregate, and consider the case where the table is still empty:
INSERT INTO roombooking("hotelbookingID", …)
VALUES ( COALESCE((SELECT max("hotelbookingID") FROM roombooking), 0) + 1, …);
Upvotes: 0