Записи курсор в PostgreSQL

Я пытаюсь использовать курсор для запроса, объединяющего несколько таблиц. Я видел, что для 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;

ошибки я получаю это:

ERROR:  relation "xyz" does not exist
CONTEXT:  compilation of PL/pgSQL function "avoidable_states" near line 4

2 ответов


просто использовать RECORD тип:

DECLARE
    ...
    cur_row RECORD;
BEGIN
    ...
    FETCH xyz INTO cur_row;
    EXIT WHEN NOT FOUND;
    IF cur_row.city LIKE 'CH%' THEN
        ...

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;

в сторону: в функции нет ничего, что нуждалось бы волатильность VOLATILE. Использовать STABLE.

2. Set-based подходи!--8-->

почти всегда лучше использовать подход на основе набора если это возможно. Использовать 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;

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;