1

私はPostgreSQLでこのようなことをしたいと思っています。

私はこれを試しました:

CREATE or replace FUNCTION create_patient(_name text, _email text, _phone text
     , _password text
     , _field1 text, _field2 text, _field3 timestamp, _field4 text
     , OUT _pid integer, OUT _id integer
    ) RETURNS record AS
$$
DECLARE
    _id integer;
    _type text;
    _pid integer;
BEGIN
    _type := 'patient';

    INSERT into patients (name, email, phone, field1, field2, field3)
    VALUES (_name, _email, _phone, _field1, _field2, _field3)
    RETURNING id into _pid;

    INSERT into users (username, password, type, pid, phone, language)
    VALUES (_email, _password, _type, _pid, _phone, _field4)
    RETURNING id into _id;
END;
$$ LANGUAGE plpgsql;

field1 / field2 / field3 / field4しかし、いくつかを指定したくない場合や、指定されていないフィールドにテーブルのデフォルト値を使用したい場合がたくさんあります。この関数を呼び出すには、すべてのフィールドを指定する必要があるため、現在それは不可能です。

挿入するフィールドを指定できる PL/pgSQLのラッパー プロシージャを作成する簡単な方法はありINSERTますか?

4

1 に答える 1

6

関数パラメーターと動的 SQLにデフォルト値を使用する...

デモ機能

CREATE OR REPLACE FUNCTION create_patient(
     _name     text      = NULL  -- always updated, NULL if not provided
    ,_email    text      = NULL
    ,_phone    text      = NULL
    ,_password text      = NULL
    ,_field1   text      = NULL  -- variable parameters
    ,_field2   text      = NULL
    ,_field3   timestamp = NULL
    ,_language text      = NULL
    ,_cols     text[]    = '{field1,field2,field3,language}'
    ,OUT _pid  text
    ,OUT _id   int)
  RETURNS record AS
$func$
BEGIN
   EXECUTE format(
   'INSERT INTO patients (field1, field2, field3, name, email, phone)
    VALUES               (%s,     %s,     %s,     $4,   $5,    $6   )
    RETURNING id'
       ,CASE WHEN 'field1' = ANY(_cols) THEN '$1' ELSE 'DEFAULT' END
       ,CASE WHEN 'field2' = ANY(_cols) THEN '$2' ELSE 'DEFAULT' END
       ,CASE WHEN 'field3' = ANY(_cols) THEN '$3' ELSE 'DEFAULT' END)
    INTO  _pid                       -- return value, also used in 2nd insert
    USING _field1, _field2, _field3, _name, _email, _phone;

   EXECUTE format(
   'INSERT INTO users (username, password, type,        pid, phone, language)
    VALUES            ($1,       $2,       $$patient$$, $3,  $4,    %s      )
    RETURNING id'
      ,CASE WHEN 'language' = ANY(_cols) THEN '$4' ELSE 'DEFAULT' END)
    INTO  _id                        -- return value
    USING _email, _password, _pid, _phone, _language;
END
$func$  LANGUAGE plpgsql;

電話

SELECT * FROM create_patient('myname','myemail','myphone','mypassword'
,'myfield1','myfield2',NULL,'English','{field2,language,field1}'::text[]);

関数は名前付きパラメーターを使用し、それぞれにデフォルト値があるため、次のように呼び出すこともできます。

SELECT * FROM create_patient(_name := 'myname');

null 以外の値が必要な場合はテーブルで機能しない可能性がありますが、名前付きパラメーターを指定すると、デフォルトでパラメーターを省略できることを示します。省略されたパラメーターは、宣言されたとおりのデフォルト値を取ります (列のデフォルトと混同しないでください)。この関連する回答の詳細:
可変数の入力パラメーターを持つ関数

主なポイント

  • コマンドのDEFAULTキーワードINSERTを利用します。システムにテーブルの列のデフォルトを挿入させます。別の方法として、行内の対応するアイテムを取得する行内
    の列のみをリストすることもできます。INSERTVALUES

  • 動的 SQLを使用し、値だけでなくステートメント自体を操作する必要があります。EXECUTE

  • 「スイングコラム」はfield1とでfield3ありlanguage、残りは定義に従って配線されています。必要に応じて変更します。

  • 私の関数はすべてのケースNULLで機能します。列のデフォルトの代わりに値を指定することもできます。_colsこれには、挿入する列の情報を提供するパラメーターが必要です。

  • 関連するすべての列が宣言されNOT NULLている場合 (明確化されていません)、簡略化できます。NULL列のデフォルトを取得する必要がある列に渡し、CASEステートメントを適応させます。

  • を省略する_colsと、すべてのフィールドが挿入されます。_cols最後のINパラメータであり、デフォルト値があるため、いつでも省略できます。

  • パラメータを値として渡し、動的に構築されたクエリ文字列による SQL インジェクションを防ぐためにUSINGfor 句EXECUTEを使用します。

  • format()ステートメントの組み立てを簡素化し、複数の代入を避けるために採用しています。PL/pgSQL の方が安価です。

  • ヘッダーのパラメーターによって宣言され、自動的に返されるため、関数本体ではDECLARE _idandを使用しないでください。_pidOUT

  • ステートメントに定数値を直接type挿入できます。INSERTこの方法では、変数は必要なく、追加の割り当てを保存できます。

  • PostgreSQL 9.1でテスト済みですが、8.4 以降のすべてのバージョンで動作するはずです - format()9.1 で導入されたものを除きます。

于 2012-06-23T15:12:36.113 に答える