web-dev-qa-db-fra.com

Enregistrements basés sur le curseur dans PostgreSQL

J'essaie d'utiliser des curseurs pour une requête qui joint plusieurs tables. J'ai vu que pour Oracle, il existe un enregistrement basé sur le curseur. Lorsque j'essaie de même pour Postgres, cela génère une erreur. Comment puis-je faire de même dans 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;

L'erreur que j'obtiens est:

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

Utilisez simplement le type RECORD:

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

1. Curseur implicite

Il est presque toujours préférable d'utiliser le curseur implicite d'une boucle FOR plutôt que de recourir à une boucle un peu plus lente et un curseur explicite peu maniable. J'ai écrit des milliers de fonctions plpgsql et seule une main pleine de curseurs explicites a du sens.

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;

A part: il n'y a rien dans la fonction qui aurait besoin de volatilité VOLATILE . Utilisez STABLE.

2. Approche basée sur les ensembles

Il est presque toujours préférable d'utiliser une approche basée sur un ensemble si possible. Utilisation RETURN QUERY pour retourner directement comme défini à partir d'une requête.

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. Fonction SQL

Pour le cas simple (probablement une simplification), vous pouvez également utiliser un simple fonction SQL ou même simplement la requête:

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;
32
Erwin Brandstetter