sql >> データベース >  >> RDS >> PostgreSQL

PostgreSQLのレコード変数の列名を動的に渡す

    このダミーテーブルの操作

    CREATE TEMP TABLE foo (id int, my_num numeric);
    INSERT INTO foo VALUES (1, 12.34)
    

    まず、あなたの例を単純化してサニタイズしました:

    • 質問に関係のないノイズを削除しました。

    • RETURNS SETOF void ほとんど意味がありません。 RETURNS voidを使用しています 代わりに。

    • textを使用しています character varyingの代わりに 、簡単にするためです。

    • 動的SQLを使用する場合は、 SQLインジェクションから保護するために、私はformat()を使用します %Iを使用 この場合。他にも方法があります。

    基本的な問題は、SQLが型と識別子に対して非常に厳格であるということです。 動的テーブルを使用して操作しています 名前とレコードの動的フィールド名 -匿名 記録 元の例では。 Pl / pgSQLは、これに対処するための十分な機能を備えていません。 Postgresは内部が何であるかを知りません 匿名の記録。レコードをよく知られているタイプに割り当てた後でのみ 個々のフィールドを参照できますか。
    これは、設定しようとしている密接に関連した質問です。 動的な名前のレコードのフィールド:
    動的SQLを使用して複合変数フィールドの値を設定する方法

    基本機能

    CREATE OR REPLACE FUNCTION getrowdata1(table_name text, id int)
      RETURNS void AS
    $func$ 
    DECLARE
       srowdata record;
       reqfield text := 'my_num';   -- assigning at declaration time for convenience
       value    numeric;
    BEGIN
    
    RAISE NOTICE 'id: %', id; 
    
    EXECUTE format('SELECT * FROM %I WHERE id = $1', table_name)
    USING  id
    INTO   srowdata;
    
    RAISE NOTICE 'srowdata: %', srowdata;
    
    RAISE NOTICE 'srowdatadata.my_num: %', srowdata.my_num;
    
    /* This does not work, even with dynamic SQL
    EXECUTE format('SELECT ($1).%I', reqfield)
    USING srowdata
    INTO value;
    
    RAISE NOTICE 'value: %', value;
    */
    
    END
    $func$ LANGUAGE plpgsql;
    

    電話:

    SELECT * from getrowdata1('foo', 1);
    

    コメントされた部分は例外を発生させます:

    レコードデータ型の列「my_num」を識別できませんでした:SELECT * fromgetrowdata(1、'foo')

    hstore

    追加のモジュールhstoreをインストールする必要があります このため。データベースごとに1回:

    CREATE EXTENSION hstore;
    

    そうすれば、すべてが次のように機能する可能性があります:

    CREATE OR REPLACE FUNCTION getrowdata2(table_name text, id int)
      RETURNS void AS
    $func$ 
    DECLARE
       hstoredata hstore;
       reqfield   text := 'my_num';
       value      numeric;
    BEGIN
    
    RAISE NOTICE 'id: %', id; 
    
    EXECUTE format('SELECT hstore(t) FROM %I t WHERE id = $1', table_name)
    USING  id
    INTO   hstoredata;
    
    RAISE NOTICE 'hstoredata: %', hstoredata;
    
    RAISE NOTICE 'hstoredata.my_num: %', hstoredata -> 'my_num';
    
    value := hstoredata -> reqfield;
    
    RAISE NOTICE 'value: %', value;
    
    END
    $func$ LANGUAGE plpgsql;
    

    電話:

    SELECT * from getrowdata2('foo', 1);
    

    ポリモーフィックタイプ

    追加のモジュールをインストールせずに代替。

    レコード変数に行全体を選択するため、明確に定義されたタイプがあります。 定義ごとにそれのために。これを使って。キーワードは多形型です 。

    CREATE OR REPLACE FUNCTION getrowdata3(_tbl anyelement, id int)
      RETURNS void AS
    $func$ 
    DECLARE
       reqfield text := 'my_num';
       value    numeric;
    BEGIN
    
    RAISE NOTICE 'id: %', id; 
    
    EXECUTE format('SELECT * FROM %s WHERE id = $1', pg_typeof(_tbl))
    USING  id
    INTO   _tbl;
    
    RAISE NOTICE '_tbl: %', _tbl;
    
    RAISE NOTICE '_tbl.my_num: %', _tbl.my_num;
    
    EXECUTE 'SELECT ($1).' || reqfield   -- requfield must be SQLi-safe or escape
    USING _tbl
    INTO  value;
    
    RAISE NOTICE 'value: %', value;
    
    END
    $func$ LANGUAGE plpgsql;
    

    電話:

    SELECT * from getrowdata3(NULL::foo, 1);
    

    -> SQLfiddle

    • 入力パラメータ_tblを(ab-)使用します 3 ここでの目的:

      • 明確に定義されたタイプを提供します 記録の
      • 名前を提供します テーブルの、自動的にスキーマ修飾されます
      • 変数として機能します。
    • この関連する回答(最後の章)の詳細な説明:
      PL / pgSQL関数をリファクタリングして、さまざまなSELECTクエリの出力を返します




    1. LIMITを使用するときに行の総数を取得しますか?

    2. SELECTステートメントの2行間のMySQLの違い

    3. SQLServerで「値をデータ型に変換するときに変換に失敗しました」を修正する方法

    4. MySQLデータベースがクラッシュしたのはなぜですか?新しいMySQLフリーズフレームで洞察を得る