我在PostgreSQL 9.6上有一些函数返回游标(refcursor):
CREATE OR REPLACE FUNCTION public.test_returning_cursor()
RETURNS refcursor
IMMUTABLE
LANGUAGE plpgsql
AS $$
DECLARE
_ref refcursor = 'test_returning_cursor_ref1';
BEGIN
OPEN _ref FOR
SELECT 'a' :: text AS col1
UNION
SELECT 'b'
UNION
SELECT 'c';
RETURN _ref;
END
$$;
我需要编写另一个函数,在该函数中创建临时表,并将来自此refcursor的所有数据插入其中.但INSERT INTO … FETCH ALL FROM …似乎是不可能的.这样的功能无法编译:
CREATE OR REPLACE FUNCTION public.test_insert_from_cursor()
RETURNS table(col1 text)
IMMUTABLE
LANGUAGE plpgsql
AS $$
BEGIN
CREATE TEMP TABLE _temptable (
col1 text
) ON COMMIT DROP;
INSERT INTO _temptable (col1)
FETCH ALL FROM "test_returning_cursor_ref1";
RETURN QUERY
SELECT col1
FROM _temptable;
END
$$;
我知道我可以使用:
FOR _rec IN
FETCH ALL FROM "test_returning_cursor_ref1"
LOOP
INSERT INTO ...
END LOOP;
但有更好的方法吗?
最佳答案 不幸的是,INSERT和SELECT无法访问整个游标.
为避免昂贵的单行INSERT,您可以使用RETURNS TABLE的中间函数,并使用RETURN QUERY将光标作为表返回.看到:
> Return a query from a function?
CREATE OR REPLACE FUNCTION f_cursor1_to_tbl()
RETURNS TABLE (col1 text) AS
$func$
BEGIN
-- MOVE BACKWARD ALL FROM test_returning_cursor_ref1; -- optional, see below
RETURN QUERY
FETCH ALL FROM test_returning_cursor_ref1;
END
$func$ LANGUAGE plpgsql; -- not IMMUTABLE
然后直接创建临时表,如:
CREATE TEMP TABLE t1 ON COMMIT DROP
AS SELECT * FROM f_cursor1_to_tbl();
看到:
> Creating temporary tables in SQL
仍然不是很优雅,但比单行INSERT快得多.
注意:由于源是游标,因此只有第一次调用成功.第二次执行该函数将返回一个空集.你需要一个带有SCROLL
option的光标,然后移动到重复调用的开始.