使用变量来确定 Postgres 中 select 中的列名

Gus*_*lfo 5 postgresql scripting dynamic-sql select

我正在尝试从旧表创建新表结构的更新,但不使用函数。我正在尝试为其创建一个脚本。旧表是这样的:

旧表 ( OldTable)

姓名 可乐 列b 列_c
ABC 0 无效的 1
DEF 1 1 1
生长激素指数 无效的 1 0

并且,新表:

Users:

ID 姓名
1 ABC
2 DEF
3 生长激素指数

Rules:

ID 规则名称
1 可乐
2 列b
3 列_c
4 寒冷的

UserRule

ID_USER ID_规则

因此,我需要使用 TableMix 上的选择结果填充表 UserRules,其中用户名等于表 User 上的用户名,并且 TableMix 中列 <col_name> 的值等于 1。(select <col_name>来自 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 numeric 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 $$
Run Code Online (Sandbox Code Playgroud)

在此之后,我没有任何进展。

更新

这样我就可以获得真正的价值:

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 $$
Run Code Online (Sandbox Code Playgroud)

结果为实整数值。

但如果我对用户名使用循环,它就不起作用。

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 $$
Run Code Online (Sandbox Code Playgroud)

所以,结果总是 。我哪里错了?

Cra*_*ger 3

我想您可能正在寻找以下USING条款:

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

您使用$1$2等作为放置参数,并通过 传递USING。您使用%I由 扩展的迭代器format

更新:如果你想合并列名(ruleName如果它为空),也许你想要更多类似的东西:

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

??

您需要考虑评估顺序。生成的 SQL 的哪些部分以及为了创建该 SQL 而评估哪些内容?