【问题标题】:PostgreSQL 11 - using format to assign to variablePostgreSQL 11 - 使用格式分配给变量
【发布时间】:2020-04-18 17:19:06
【问题描述】:

我的睡眠时间远远超出了我的日程安排,我已经被这个问题困扰了很长时间,我什至不知道我在寻找什么来解决,但我希望使用格式来插入我想要的值'将用于列名,然后执行它......但无论我尝试如何更改它,它都会不断给我错误:c

这是我试图做一些不起作用的事情的部分,但我认为你明白我想要实现的目标

    ratelimit := EXECUTE format('(SELECT %I
                      FROM users.ratelimits 
                      WHERE user_id = $2)
                     ', $1);

这是勇敢者的完整代码

CREATE OR REPLACE FUNCTION users.consume_ratelimit(_name text,__user_id integer)
    RETURNS boolean
    LANGUAGE 'plpgsql'
    VOLATILE
    PARALLEL UNSAFE
    COST 100
AS $BODY$DECLARE
    ratelimit INTEGER;
    reset_timeout timestamptz;
    premium BOOLEAN;
BEGIN
    ratelimit := EXECUTE format('(SELECT %I
                      FROM users.ratelimits 
                      WHERE user_id = $2)
                     ', $1);

    reset_timeout := EXECUTE format('(SELECT %I_refresh 
                      FROM users.ratelimits 
                      WHERE user_id = $2)
                     ', $1);

    premium := (SELECT users.is_premium($2));


    IF premium THEN
        RETURN TRUE;

    ELSIF reset_timeout <= NOW() THEN
        UPDATE users.ratelimits
        SET image_refresh = NOW() + '1 hour'::interval,
            image = DEFAULT
            WHERE user_id = $2;
        RAISE NOTICE 'reset';
        RETURN TRUE;

    ELSE
        IF ratelimit > 0 THEN
            EXECUTE format('UPDATE users.ratelimits
            SET %I = %I - 1
            WHERE user_id = $2', $1, $1);
            RAISE NOTICE 'decrement';
            RETURN TRUE;

        ELSIF ratelimit <= 0 THEN
            RAISE NOTICE 'out of credits';
            RETURN FALSE;

        ELSE
            EXECUTE format('INSERT INTO users.ratelimits(user_id) VALUES ($2)
            ON CONFLICT DO UPDATE SET
                %I = excluded.%I,
                %I_refresh = excluded.%I_refresh', $1, $1, $1, $1);
            RAISE NOTICE 'create';
            RETURN TRUE;

        END IF;
    END IF;
END;$BODY$;

【问题讨论】:

  • 它是函数的一部分吗?能贴出完整的功能代码吗?
  • @SlavaRozhnev 添加了完整的代码,但它太丑了,只有它自己的妈妈会喜欢它

标签: sql postgresql postgresql-11


【解决方案1】:

As documented in the manual 您需要将into 与 EXECUTE 一起使用以将结果存储到变量中。这也可以处理多个列/变量,因此您只需要一个 EXECUTE 即可获取两个值。

为清楚起见,您应该按名称引用参数,而不是按位置。

EXECUTE format('SELECT %I, %I_refresh 
                FROM users.ratelimits WHERE user_id = $1'), 
                _name, _name)
   USING __user_id
   INTO ratelimit, reset_timeout;

注意format()字符串中的$1是执行SQL语句时使用的参数占位符,将替换为USING子句中指定的变量值。

没有 SELECT 的变量赋值也更有效:

premium := users.is_premium(__user_id);

【讨论】:

    【解决方案2】:

    似乎some_var := EXECUTE ... 不起作用。此外,EXECUTE 语句中的参数与函数中的参数不同 - 您需要将它们提供给执行语句。

    我没有测试过,但也许

    -- q declared above as text
    
    q := format('
      SELECT %I
      FROM users.ratelimits 
      WHERE user_id = %s;
    ', $1, $2);
    
    EXECUTE q INTO ratelimit;
    

    会有用吗?我还从查询中删除了括号,这些是不必要的,并且可能是问题本身。

    我已经测试了函数

    CREATE OR REPLACE FUNCTION test_sum (a int, b int)
    RETURNS int
    AS $$
    DECLARE
      q text; 
      result int;
    BEGIN
      q := FORMAT ('SELECT %s + %s', $1, $2);
      EXECUTE q INTO result;
      RETURN result;
    END
    $$ LANGUAGE plpgsql
    

    这确实有效。如果我上面的建议不起作用,也许你可以从上面的开始。

    【讨论】:

      猜你喜欢
      • 2015-05-23
      • 2015-07-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-05-11
      • 1970-01-01
      相关资源
      最近更新 更多