web-dev-qa-db-ja.com

Postgres plpgsql-動的作成ステートメント内での変数の使用

Postgres pl/pgsqlを使用して、次のような動的EXECUTEコマンドを使用してテーブルを作成しようとしています。

 ...
 DECLARE
    tblVar varchar := "myTable";
 BEGIN
 EXECUTE 'CREATE TABLE $1 ( 
             foo integer NOT NULL, 
             bar varchar NOT NULL)'
 USING _tblVar;
 ...

ただし、引き続きエラーメッセージが表示される

エラー:「$ 1」またはその近くの構文エラー

$1トークンを使用せず、代わりに文字列myTableを書き込むと、問題なく動作します。

CREATE呼び出しでの動的ステートメントの使用に制限はありますか?

8
Jmoney38

@filipremが書いたものに加えて、これを正しく行う方法を次に示します。

_...
DECLARE
   tbl_var text := 'myTable';   -- I would not use mixed case names ..
BEGIN
EXECUTE '
CREATE TABLE ' || quote_ident(tbl_var) || '( 
   foo integer NOT NULL, 
   bar text NOT NULL)';
...
_

quote_ident() を使用して、SQLインジェクションまたは構文エラーを回避します。非標準文字または予約語で名前を引用します。

また、例の文字列値の前後にある二重引用符を single-quotes に置き換えました。

5

http://www.postgresql.org/docs/9.1/static/plpgsql-statements.html#PLPGSQL-STATEMENTS-EXECUTING-DYN を参照してください

パラメータシンボルはデータ値にのみ使用できることに注意してください。動的に決定されるテーブルまたは列の名前を使用する場合は、それらをコマンド文字列にテキストで挿入する必要があります。たとえば、動的に選択されたテーブルに対して前述のクエリを実行する必要がある場合は、次のようにすることができます。

EXECUTE 'SELECT count(*) FROM '
    || tabname::regclass
    || ' WHERE inserted_by = $1 AND inserted <= $2'
   INTO c
   USING checked_user, checked_date;

以下のコメントに記載されているように、キャストメソッドは、特にCREATEステートメントの場合、常に実行可能であるとは限りません。 format関数について考えてみましょう。次に例を示します。

EXECUTE format(
  'CREATE TABLE %I (%I %I, %I %I)',
  v_tabname,
  v_col1name, v_col1type,
  v_col2name, v_col2type);

言い換えると:

はい、そのような制限があります。テーブル/列名にパラメーターを使用することはできません。これは、動的SQLステートメントのコンパイル時にPostgresqlがクエリを解析できる必要があるためです。パーサーは、使用されている関係を識別できなければなりません。

補足:この制限は、おそらくOracleを含む他のDBMSの動的SQLに適用されます: http://download.Oracle.com/docs/cd/B19306_01/appdev.102/b14261/dynamic.htm#CHDHGHIF =

3
filiprem