web-dev-qa-db-ja.com

変数を使用して、postgreのselectで列の名前を決定します

古いテーブルから新しいテーブル構造の更新を作成しようとしていますが、関数は使用していません。私はそれにスクリプトを作成しようとしています。古いテーブルは次のとおりです。

-- old table (OldTable)
name| col_a | col_b | col_c |
--------|---------|---------|--------|
ABC  |     0    |NULL |    1    |
DEF  |     1    |    1     |    1   |
GHI   | NULL |    1    |     0   |

And, new tables:
-- Table Users

ID | NAME
----| ---------
 1  | ABC
 2  | DEF
 3  | GHI

-- Table Rules
ID | RULE_NAME
--- | ------------------
 1  | col_a
 2  | col_b
 3  | col_c
 4  | col_d

-- Table UserRules
ID_USER | ID_RULE
------------- |-------------

したがって、ユーザー名がテーブルユーザーのユーザー名と等しく、テーブルミックスの列の値が1と等しいTableMixでの選択からの結果をテーブルUserRulesに入力する必要があります(OldTableからOldTable.nameを選択します) = Users.name)。まあ、私はこれを試しています:

DO $$
    DECLARE rules CURSOR FOR SELECT column_name FROM information_schema.columns
        WHERE table_schema = 'public' AND table_name   = 'OldTable' 
        AND data_type = 'numeric' AND column_name NOT IN ('foo','bar'); 
        -- "foo" and "bar" are another numerc cols, but not define rules.
    DECLARE users CURSOR FOR SELECT name FROM public.Users;
    BEGIN
        FOR ruleName IN rules LOOP
            FOR userName IN users LOOP
                EXECUTE format('SELECT COALESCE(%I,col,$1) FROM public.OldTable 
                    WHERE name = ''$2''', ruleName, username);      
                -- insert on... populate the table Rules after get the id of the rule in table Rules if the result of select in OldTable equals 1 (or true if has a "where ... = 1")
            END LOOP;
        END LOOP;
END $$

この後、私は進歩していません...誰かが私を助けますか?よろしく!

[〜#〜]更新[〜#〜]

このようにして、本当の価値を得ることができます:

DO $$
DECLARE 
    rules CURSOR FOR SELECT column_name FROM information_schema.columns
    WHERE table_schema = 'public' AND table_name   = 'oldtable' AND data_type = 'numeric'
    AND column_name NOT IN ('foo','bar');

    names CURSOR FOR SELECT username FROM public.users;

    res integer;
BEGIN
    FOR rulename IN rules LOOP          
        EXECUTE format('SELECT %s FROM oldtable WHERE nome = %L', rulename, 'USER NAME')    INTO res;
    -- IF res > 0 THEN
       RAISE NOTICE '%', res;
    --END IF;
    END LOOP;
END $$

結果は実際の整数値です。

しかし、ユーザー名にループを使用すると、機能しません。

DO $$
DECLARE 
    rules CURSOR FOR SELECT column_name FROM information_schema.columns
    WHERE table_schema = 'public' AND table_name   = 'oldtable' AND data_type = 'numeric'
    AND column_name NOT IN ('foo','bar');

    names CURSOR FOR SELECT username FROM public.users;

    res integer;
BEGIN
    FOR name IN names LOOP
        FOR rulename IN rules LOOP          
            EXECUTE format('SELECT %s FROM oldtable WHERE nome = %L', rulename, name)   INTO res;
        -- IF res > 0 THEN
           RAISE NOTICE '%', res;
        --END IF;
        END LOOP;
    END LOOP;
END $$

したがって、resulは常にです。どこがいけないの?

3
GustavoAdolfo

USING句を探していると思います。

EXECUTE format('SELECT COALESCE(%I,col,$1) FROM public.TableMix 
                WHERE name = $2', ruleName)
        USING (username, whateverTheSecondParameterIs);      

あなたが使う $1$2など、配置パラメータの場合、USINGによって渡されます。あなたが使う %Iは、formatによって拡張された識別子。

更新:列名を合体させたい場合ruleNameがnullの場合、おそらく次のようなものが必要です。

EXECUTE format('SELECT %I FROM public.TableMix 
                WHERE name = $1', coalesce(ruleName, 'col'))
        USING (username); 

??

評価の順序について考える必要があります。生成されたSQLの一部、およびそのSQLを作成するために何が評価されますか?

2
Craig Ringer