PostgreSQL中基于游标的记录

Zeu*_*eus 13 postgresql loops plpgsql cursor

我正在尝试使用游标来连接多个表的查询.我已经看到oracle有一个基于游标的记录.当我为Postgres尝试相同时,它会抛出一些错误.我怎么能在Postgres做同样的事情?

CREATE OR REPLACE FUNCTION avoidable_states()
RETURNS SETOF varchar AS
$BODY$
DECLARE
    xyz CURSOR FOR select * from address ad
                            join city ct on ad.city_id = ct.city_id;    
    xyz_row RECORD;
BEGIN   
    open xyz;

    LOOP
    fetch xyz into xyz_row;
        exit when xyz_row = null;
        if xyz_row.city like '%hi%' then
            return next xyz_row.city;               
        end if;
    END LOOP;
    close xyz;  
END;
$BODY$
  LANGUAGE plpgsql VOLATILE;
Run Code Online (Sandbox Code Playgroud)

我得到的错误是:

ERROR:  relation "xyz" does not exist
CONTEXT:  compilation of PL/pgSQL function "avoidable_states" near line 4
Run Code Online (Sandbox Code Playgroud)

Erw*_*ter 32

1.隐含光标

使用FOR循环的隐式游标几乎总是比使用稍微慢一些的笨拙的显式游标更好.我已经编写了数千个plpgsql函数,并且只有一手完全明确的游标才有意义.

CREATE OR REPLACE FUNCTION avoidable_states()
  RETURNS SETOF varchar AS
$func$
DECLARE
    rec record;
BEGIN   
   FOR rec IN
      SELECT *
      FROM   address ad
      JOIN   city    ct USING (city_id)
   LOOP
      IF rec.city LIKE '%hi%' THEN
          RETURN NEXT rec.city;               
      END IF;
   END LOOP;
END
$func$  LANGUAGE plpgsql STABLE;
Run Code Online (Sandbox Code Playgroud)

除此之外:函数中没有任何东西需要波动性VOLATILE.使用STABLE.

2.基于集合的方法

如果可能的话,使用基于集合的方法几乎总是更好.用于RETURN QUERY直接从查询中返回设置.

CREATE OR REPLACE FUNCTION avoidable_states()
  RETURNS SETOF varchar AS
$func$
BEGIN   
   RETURN QUERY
   SELECT ct.city
   FROM   address ad
   JOIN   city    ct USING (city_id)
   WHERE  ct.city LIKE '%hi%';
END
$func$  LANGUAGE plpgsql STABLE;
Run Code Online (Sandbox Code Playgroud)

3. SQL函数

对于简单的情况(可能是简化),您可能还使用简单的SQL函数甚至只是查询:

CREATE OR REPLACE FUNCTION avoidable_states()
  RETURNS SETOF varchar AS
$func$
   SELECT ct.city
   FROM   address ad
   JOIN   city    ct USING (city_id)
   WHERE  ct.city LIKE '%hi%';
$func$  LANGUAGE sql STABLE;
Run Code Online (Sandbox Code Playgroud)


Mat*_*sOl 6

只需使用RECORD类型:

DECLARE
    ...
    cur_row RECORD;
BEGIN
    ...
    FETCH xyz INTO cur_row;
    EXIT WHEN NOT FOUND;
    IF cur_row.city LIKE 'CH%' THEN
        ...
Run Code Online (Sandbox Code Playgroud)