我想編寫一個執行select查詢的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'實際上完成了這個功能,它只是不返回任何數據,你需要'RETURN NEXT'或'RETURN QUERY'。 – Patrick