PostgreSQL 11 - использование формата для присвоения переменной - PullRequest
0 голосов
/ 18 апреля 2020

Я проснулся намного дольше, чем планировал, и я застрял с этой проблемой в течение долгого времени, я даже не знаю, что я ищу, чтобы решить, но я sh использую формат для вставки значения, которые я буду использовать для имен столбцов, а затем выполнять их ... но это продолжает давать мне ошибки, независимо от того, сколько я пытаюсь изменить его: 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$;

Ответы [ 2 ]

1 голос
/ 18 апреля 2020

Как указано в руководстве , вам необходимо использовать 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;

Обратите внимание, что $1 внутри строки для format() является заполнителем параметра, используемым при выполнении оператора SQL, и будет заменен значением переменной, указанной в USING пункт.

Назначение переменной также более эффективно без SELECT:

premium := users.is_premium(__user_id);
0 голосов
/ 18 апреля 2020

Кажется, some_var := EXECUTE ... не будет работать. Кроме того, параметры внутри оператора 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

, и она работает. Если мое предложение выше не работает, возможно, вы можете использовать вышеупомянутое в качестве отправной точки.

...