0

次のplpgsqlプロシージャがあります。

DECLARE 
     _r record;
     point varchar[] := '{}';
     i int := 0;

BEGIN



FOR _r IN EXECUTE ' SELECT a.'|| quote_ident(column) || ' AS point,
       FROM ' || quote_ident (table) ||' AS a'
LOOP

       point[i] = _r;
       i = i+1;

END LOOP;

RETURN 'OK';
END;

その主な目的は、テーブルをトラバースし、行の各値を配列に格納することです。私はまだplpgsqlを初めて使用します。誰かが私に次のエラーを与えているので、エラーであると指摘できますか? ここに画像の説明を入力してください

4

2 に答える 2

1

これは完全な構文です(パラメーターの名前columnを予約語に変更したことに注意してください。同じことが)にも当てはまります。col_namecolumntable

create or replace function foo(col_name text, table_name text)
  returns text
as
$body$

DECLARE 
     _r record;
     point character varying[] := '{}';
     i int := 0;

BEGIN
    FOR _r IN EXECUTE 'SELECT a.'|| quote_ident(col_name) || ' AS pt, FROM ' || quote_ident (table_name) ||' AS a'
    loop
     point[i] = _r;
     i = i+1;
   END LOOP;

   RETURN 'OK';
END;
$body$
language plpgsql;

正直に言うと、私は失敗するので、ここで何を達成しようとしているのか見てみましょう。

于 2013-02-19T09:51:52.700 に答える
0

@a_horseは、試行の失敗に関する重大な問題のほとんどを修正します。

ただし、誰もこれを使用しないでください。次の段階的な手順は、最新の PostgreSQL を使用した適切な実装につながるはずです。

フェーズ 1: エラーといたずらを取り除く

  • リストの後のコンマを削除してSELECT、構文エラーを修正します。

  • 配列を0で開始しますが、デフォルトでは で開始し1ます。これは、必要な場合にのみ行ってください。array_upper()らと操作すると、予期しない結果につながります。代わりに開始し1ます。

  • RETURNアセンブルされた配列を返すようにタイプを変更しvarchar[]て、このデモを便利にします。

これまでのところ:

CREATE OR REPLACE FUNCTION foo(tbl varchar, col varchar)
  RETURNS varchar[] LANGUAGE plpgsql AS
$BODY$
DECLARE 
   _r record;
   points varchar[] := '{}';
   i int := 0;
BEGIN
   FOR _r IN
      EXECUTE 'SELECT a.'|| quote_ident(col) || ' AS pt
      FROM ' || quote_ident (tbl) ||' AS a'
   LOOP
      i = i + 1;        -- reversed order to make array start with 1
      points[i] = _r;
   END LOOP;

   RETURN points;
END;
$BODY$;

フェーズ 2: 不要なものを取り除き、役立つものにする

  • 簡単にするために/のtext代わりに使用します。ただし、どちらでも機能します。character varyingvarchar

  • 単一の列を選択していますが、 type の変数を使用していますrecord。このようにして、レコード全体が に強制されtextます。これには、周囲の括弧が含まれます。ほとんど意味がありません。text代わりに変数を使用してください。( )に明示的にキャストすると、どの列でも機能します。任意の型を にキャストできます。text::texttext

  • 変数を初期化しても意味がありませんpoint。ここから始められNULLます。

  • この場合、内部のテーブルと列のエイリアスEXECUTEは役に立ちません。動的に実行される SQL には独自のスコープがあります。

  • plpgsql 関数の final の後にセミコロン ( ;) は必要ありません。END

  • を使用して各値を配列に追加する方が簡単||です。

ほとんど正気です:

CREATE OR REPLACE FUNCTION foo1(tbl text, col text)
  RETURNS text[] LANGUAGE plpgsql AS
$func$
DECLARE 
   point  text;
   points text[];
BEGIN
   FOR point IN
      EXECUTE 'SELECT '|| quote_ident(col) || '::text FROM ' || quote_ident(tbl)
   LOOP
      points = points || point;
   END LOOP;

   RETURN points;
END
$func$;

フェーズ 3: 最新の PL/pgSQL で輝かせる

  • テーブル名を として渡すとtext、あいまいな状況が発生します。またはでSQLiを問題なく防ぐことができますが、 の外側のテーブルでは失敗します。次に、あいまいな値を作成するschema-qualification を追加する必要があります。「xy」は、テーブル名「xy」またはスキーマ修飾テーブル名「x」.「y」を表すことができます。"""x"".""y""" にエスケープされるため、"x"."y" を渡すことはできません。スキーマ名に追加のパラメーターを使用するか、タイプの 1 つのパラメーターが強制されたときに必要に応じて自動的に引用されるかのいずれかが必要であり、ここではエレガントなソリューションです。format()quote_ident()search_path
    regclass regclasstext

  • 新しいformat()ものは、複数の (または単一の)quote_ident()呼び出しよりも簡単です。

  • 順序が指定されていません。SELECTなしで任意の順序で行を返しますORDER BY。基礎となるテーブルが変更されない限り、結果は通常再現可能であるため、これは安定しているように見えるかもしれません。しかし、それは100%信頼できません。おそらく、何らかの種類のORDER BY.

  • 最後に、ループする必要はまったくありません。Array コンストラクターでプレーンSELECTを使用します。

  • OUTパラメータを使用してコードをさらに簡素化する

適切な解決策:

CREATE OR REPLACE FUNCTION f_arr(tbl regclass, col text, OUT arr text[])
 LANGUAGE plpgsql AS
$func$
BEGIN

EXECUTE format('SELECT ARRAY(SELECT %I::text FROM %s ORDER BY 1)', col, tbl)
INTO arr;

END
$func$;

電話:

SELECT f_arr('myschema.mytbl', 'mycol');
于 2013-03-10T17:48:48.630 に答える