web-dev-qa-db-ja.com

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
13
Zeus

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.暗黙カーソル

FOR loop の暗黙カーソルを使用する方が、やや遅い方法に頼るよりも、ほとんど常に優れています。扱いにくい明示カーソル。私は何千もの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;

余談:関数には volatility 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;

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