I want to convert this code in Postgres to something shorter that will do the same. I read about upsert but I couldn’t understand a good way to implement that on my code.
What I wrote works fine, but I want to find a more elegant way to write it.
Hope someone here can help me! This is the query:
CREATE OR REPLACE FUNCTION insert_table(
in_guid character varying,
in_x_value character varying,
in_y_value character varying
)
RETURNS TABLE(response boolean) LANGUAGE 'plpgsql'
DECLARE _id integer;
BEGIN
-- guid exists and it's been 10 minutes from created_date:
IF ((SELECT COUNT (*) FROM public.tbl_client_location WHERE guid = in_guid AND created_date < NOW() - INTERVAL '10 MINUTE') > 0) THEN
RETURN QUERY (SELECT FALSE);
-- guid exists but 10 minutes hasen't passed yet:
ELSEIF ((SELECT COUNT (*) FROM public.tbl_client_location WHERE guid = in_guid) > 0) THEN
UPDATE
public.tbl_client_location
SET
x_value = in_x_value,
y_value = in_y_value,
updated_date = now()
WHERE
guid = in_guid;
RETURN QUERY (SELECT TRUE);
-- guid not exist:
ELSE
INSERT INTO public.tbl_client_location
( guid , x_value , y_value )
VALUES
( in_guid, in_x_value, in_y_value )
RETURNING id INTO _id;
RETURN QUERY (SELECT TRUE);
END IF;
END
2
Answers
I finally solved it. I made another function that'll be called and checked if it's already exists and the time and then I can do upsert without any problems. That's what I did at the end:
This can indeed be a lot simpler:
Assuming
guid
is definedUNIQUE
orPRIMARY KEY
, andcreated_date
is definedNOT NULL DEFAULT now()
.① Language name is an identifier – better without quotes.
② Quotes around function body were missing (invalid command). See:
③
UPDATE
only if 10 min have not passed yet. Keep in mind that timestamps are those from the beginning of the respective transactions. So keep transactions short and simple. See:④ A function with
OUT
parameter(s) and noRETURNS
clause returns a single row (record
) automatically. Your original was declared as set-returning function (0-n returned rows), which didn’t make sense. See:⑤ It’s generally better to use the special
EXCLUDED
row than to spell out values again. See:⑤ Also using short syntax for updating multiple columns. See:
⑥ To see whether a row was written use the special variable
FOUND
. Subtle difference: different from your original, you gettrue
orfalse
after the fact, saying that a row has actually been written (or not). In your original, theINSERT
orUPDATE
might still be skipped (without raising an exception) by a trigger or rule, and the function result would be misleading in this case. See:Further reading:
You might just run the single SQL statement instead, providing your values once: