PL/pgSQL 中的光标

Posted

技术标签:

【中文标题】PL/pgSQL 中的光标【英文标题】:Cursor in PL/pgSQL 【发布时间】:2016-06-04 12:32:52 【问题描述】:

我想在函数中使用游标,但我在定义一个变量时出错,请查看并帮助:)

CREATE OR REPLACE FUNCTION curson_func (
start_date timestamp,
end_date timestamp)
RETURNS SETOF integer AS $$

DECLARE
level_cursor CURSOR FOR 
SELECT
    login_event.player_id,
    registration.country_id
FROM
    "fish-tsg".registration
LEFT JOIN
    "fish-tsg".login_event USING (player_id)
WHERE
    ts >= start_date AND ts <= end_date ;

level_cursor_row "fish-tsg".login_event%ROW_TYPE;

BEGIN 
OPEN level_cursor;
LOOP FETCH level_cursor INTO level_cursor_row;
EXIT WHEN level_cursor_row = null;
END LOOP;
CLOSE level_cursor;

RETURN level_cursor_row;

END $$
LANGUAGE 'plpgsql';

我得到的错误:

ERROR:  invalid type name ""fish-tsg".login_event%ROW_TYPE"
LINE 20: level_cursor_row "fish-tsg".login_event%ROW_TYPE;

【问题讨论】:

Copying Types 另外还有与使用游标相关的错误。以this tutorial 为例。 【参考方案1】:

您使用的是哪个版本的 PostgreSQL?您的语法(除了代码中的许多错误)是非常古老的风格,现在更容易了。例如:

CREATE OR REPLACE FUNCTION cursor_func (_start_date timestamp, _end_date timestamp) RETURNS TABLE (player_id int, country_id int) AS $BODY$
DECLARE
  _level record;
BEGIN 
  FOR _level IN -- cursor is opened automatically
    SELECT login_event.player_id, registration.country_id
    FROM "fish-tsg".registration
    LEFT JOIN "fish-tsg".login_event USING (player_id)
    WHERE ts BETWEEN _start_date AND _end_date
  LOOP
    RETURN NEXT _level;
  END LOOP;
  -- note that cursor is auto-closed

  RETURN;
END;
$BODY$ LANGUAGE plpgsql;

但您可能会从根本没有光标的更简单的方法中受益:

CREATE OR REPLACE FUNCTION cursor_func (_start_date timestamp, _end_date timestamp) RETURNS TABLE (player_id int, country_id int) AS $BODY$
BEGIN 
  RETURN QUERY
    SELECT login_event.player_id, registration.country_id
    FROM "fish-tsg".registration
    LEFT JOIN "fish-tsg".login_event USING (player_id)
    WHERE ts BETWEEN _start_date AND _end_date;

  RETURN;
END;
$BODY$ LANGUAGE plpgsql;

甚至更简单:

CREATE OR REPLACE FUNCTION cursor_func (_start_date timestamp, _end_date timestamp) RETURNS TABLE (player_id int, country_id int) AS $BODY$
  SELECT login_event.player_id, registration.country_id
  FROM "fish-tsg".registration
  LEFT JOIN "fish-tsg".login_event USING (player_id)
  WHERE ts BETWEEN $1 AND $2
$BODY$ LANGUAGE sql;

【讨论】:

【参考方案2】:

我有新的东西,但我收到只有一行。问题出在哪里?

CREATE OR REPLACE FUNCTION bi.temp_cursor()  
RETURNS refcursor AS
$BODY$
DECLARE
ref refcursor;
ref2 RECORD;

BEGIN
OPEN ref FOR SELECT player_id, ts FROM "fish-tsg".registration LIMIT 100;
FETCH ref INTO ref2;
    LOOP
        RETURN ref2;
        EXIT WHEN NOT FOUND;
    END LOOP;   
END;
$BODY$
LANGUAGE plpgsql;

SQL 查询是示例,问题是 pl/pgsql 中的游标

【讨论】:

【参考方案3】:

也许更好的方法是使用视图而不是函数。

首先,创建一个视图:

CREATE VIEW temp_view
as
SELECT
    login_event.player_id,
    registration.country_id,
    ts
FROM "fish-tsg".registration
LEFT JOIN "fish-tsg".login_event USING (player_id)

然后,使用通常放置表名的视图名执行普通选择:

select player_id, country_id
from temp_view
where ts between $start_date AND $end_date;

【讨论】:

以上是关于PL/pgSQL 中的光标的主要内容,如果未能解决你的问题,请参考以下文章

PL/pgSQL 中的“格式错误的数组文字”错误

循环通过 PL/PGSQL 中的 CURSOR 而不锁定表

PL/pgSQL 函数中的可选参数

执行 SELECT 语句并丢弃 PL/pgSQL 中的结果

PL/pgSQL 中的 EXECUTE...USING 中忽略了 USING 部分

如何在 PL/pgSQL 中的动态选择查询中使用迭代器变量?