PostgreSQL 11 - 使用格式分配给变量

PostgreSQL 11 - using format to assign to variable

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

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

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

下面是勇敢者的完整代码

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 = )
                     ', );

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

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


    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 = ;
        RAISE NOTICE 'reset';
        RETURN TRUE;

    ELSE
        IF ratelimit > 0 THEN
            EXECUTE format('UPDATE users.ratelimits
            SET %I = %I - 1
            WHERE user_id = ', , );
            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 ()
            ON CONFLICT DO UPDATE SET
                %I = excluded.%I,
                %I_refresh = excluded.%I_refresh', , , , );
            RAISE NOTICE 'create';
            RETURN TRUE;

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

看来some_var := EXECUTE ...不行。此外,EXECUTE 语句中的参数与函数中的参数不同——您需要将它们提供给 execute 语句。

我没有测试过这个,但也许

-- q declared above as text

q := format('
  SELECT %I
  FROM users.ratelimits 
  WHERE user_id = %s;
', , );

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', , );
  EXECUTE q INTO result;
  RETURN result;
END
$$ LANGUAGE plpgsql

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

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

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

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

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

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

premium := users.is_premium(__user_id);