Я хотел бы написать процедуру plpgsql, которая выполняет запрос выбора, обновляет строку (если она существует) и затем возвращает результат.plpgsql работает над запросом, прежде чем возвращать его
Для этого я хотел бы иметь возможность обрабатывать вызов процедуры как обычный запрос с помощью SELECT nickname FROM use_session_token(...)
.
Обычно я хотел бы использовать RETURN QUERY(...)
, но я хочу, чтобы обновить строку первой (это либо один или ни один, потому что token
является первичным индексом)
Но на самом деле я хочу строку только вернулся и обновляется, если другие критерии выполнены , поэтому я не могу просто работать с основным ключом.
У меня было две попытки, одна из которых использовала Refcursor
, а другая - SELECT INTO
, но я не могу фактически вернуть SETOF users
.
Моя попытка с SELECT INTO
:
CREATE OR REPLACE FUNCTION use_session_token(Char(128), Inet) RETURNS SETOF users AS $$
DECLARE
row Record;
BEGIN
SELECT u.* INTO row FROM sessions AS t
INNER JOIN users AS u ON (t.user_id = u.id)
WHERE
t.token=$1 AND
t.date_last_used > NOW() - interval '30 minutes' AND
t.ip_address=$2 AND
u.is_deleted=FALSE AND
EXISTS(
SELECT 1 FROM mail AS m
WHERE m.user_id=u.id AND m.is_confirmed=TRUE AND m.is_deleted=FALSE
)
;
IF (row) THEN
UPDATE sessions SET date_last_used=NOW() WHERE token=$1;
ELSE
-- maybe do other things if there is no result
END IF;
RETURN row;
END;
$$ LANGUAGE 'plpgsql';
Моя попытка с cursor
:
CREATE OR REPLACE FUNCTION use_session_token(Char(128), Inet) RETURNS SETOF users AS $$
DECLARE
cursor Refcursor;
row Record;
BEGIN
OPEN cursor SCROLL FOR (
SELECT u.* INTO row FROM sessions AS t
INNER JOIN users AS u ON (t.user_id = u.id)
WHERE
t.token=$1 AND
t.date_last_used > NOW() - interval '30 minutes' AND
t.ip_address=$2 AND
u.is_deleted=FALSE AND
EXISTS(
SELECT 1 FROM mail AS m
WHERE m.user_id=u.id AND m.is_confirmed=TRUE AND m.is_deleted=FALSE
)
);
FETCH cursor INTO row;
IF (FOUND) THEN
MOVE PRIOR cursor;
UPDATE sessions SET date_last_used=NOW() WHERE CURRENT OF cursor;
ELSE
-- maybe do other things if there is no result
END IF;
RETURN row;
END;
$$ LANGUAGE 'plpgsql';
Но обе попытки на самом деле не в состоянии с тем, что я на самом деле не в состоянии вернуть правильный набор результатов.
Что было бы лучшим способом решить эту проблему и решить мою проблему?
А затем, какая из этих попыток является лучшей (или является третьим решением лучше)?
Спасибо, ваш ответ действительно очень помог мне. Я на самом деле решил его с помощью 'RETURN QUERY SELECT ...', так как мне не нужна запись в этой функции. Я не знал, что RETURN не завершает процедуру. Тем не менее, обратите внимание: это 'RETURN QUERY ...', а не 'RETURN NEXT QUERY ...'. Последнее вызывает синтаксическую ошибку – h345k34cr
Рад помочь и поблагодарить за указание ошибки. Ответ исправлен. 'RETURN' фактически завершает функцию, она просто не возвращает никаких данных, для этого вам нужны« ВОЗВРАТ СЛЕДУЮЩИЙ »или« ВОЗВРАТ ЗАПРОС ». – Patrick