PostgreSQL - функция с локальными переменными - ссылка на столбец неоднозначна - PullRequest
0 голосов
/ 31 мая 2018

Я рассмотрел другие вопросы, которые соответствуют моей теме, но в моем случае двусмысленность, как мне кажется, происходит от переменной, имеющей то же имя, что и столбец.

Вот упрощенная версия функцииЯ пытаюсь создать:

CREATE OR REPLACE FUNCTION get_user_id(username TEXT) 
RETURNS INTEGER AS $$
  DECLARE
    user_id BIGINT;
    other_param TEXT;
  BEGIN
    SELECT INTO user_id user_id FROM users WHERE users.username = get_user_id.username;

    SELECT INTO other_param users.value FROM users WHERE users.user_id = user_id;

    RETURN user_id;
  END
$$ LANGUAGE PLPGSQL 

Проблема в том, что user_id в правой части WHERE рассматривается как ссылка на столбец.

Я определенно нуждаюсь в user_id в локальной переменной, так как она будет использоваться в операциях UPDATE и DELETE далее по функции, но я не получу ее как параметр, только имя пользователя.

После некоторого чтения и ранее с некоторыми проблемами с параметрами я понял, что могу использовать get_user_id.username, но это применимо только к параметрам, а не к локальным переменным (если я использую его с переменной, запрос с ошибкой, как тамне является FROM-предложением для get_user_id).

Поэтому я упускаю что-то (не очень) очевидное в использовании переменных в запросах внутри функции?

--- edit

Извинения Я упростил функцию, конечно, естьпервый запрос, который получает user_id, и эта часть работает нормально.

Ответы [ 4 ]

0 голосов
/ 31 мая 2018

Любая локальная переменная может быть квалифицирована по метке блока

create table foo(a integer);
insert into foo values(10);

do $$
<<mylabel>>
declare
  a int default 5;
  r record;
begin
  select foo.a into r
    from foo
    where foo.a = mylabel.a + 5;
  raise notice '%', r.a;
end;
$$;
NOTICE:  10
DO

Обычно все возможные конфликтные локальные переменные имеют префикс - общий префикс _.

0 голосов
/ 31 мая 2018

Я ставлю префикс параметров и переменных, чтобы они с меньшей вероятностью конфликтовали с именами столбцов:

CREATE OR REPLACE FUNCTION get_user_id (in_username TEXT) 
RETURNS INTEGER AS $$
  DECLARE
    v_user_id BIGINT;
  BEGIN
    SELECT u.user_id  INTO v_user_id FROM users u WHERE u.user_id = in_user_id;

    RETURN v_user_id;
  END
$$ LANGUAGE PLPGSQL 

Предположительно, однако, вы хотите сравнить имена пользователей:

    SELECT u.user_id  INTO v_user_id FROM users u WHERE u.username = in_username;
0 голосов
/ 31 мая 2018

https://www.postgresql.org/docs/current/static/plpgsql-implementation.html

Иногда нецелесообразно исправлять все неоднозначные ссылки в большом объеме кода PL / pgSQL.В таких случаях вы можете указать, что PL / pgSQL должен разрешать неоднозначные ссылки как переменную

и так далее ... таким образом:

t=# CREATE OR REPLACE FUNCTION get_user_id(username TEXT)
RETURNS INTEGER AS $$
#variable_conflict use_variable
  DECLARE
    user_id BIGINT;
    other_param TEXT;
  BEGIN
    SELECT INTO user_id users.user_id FROM users WHERE users.username = username;
    RETURN user_id;
  END
$$ LANGUAGE PLPGSQL
;
CREATE FUNCTION

давайте проверим:

t=# create table users (user_id int, username text);
CREATE TABLE
t=# insert into users values (1,'a');
INSERT 0 1
t=# select get_user_id('a');
 get_user_id
-------------
           1
(1 row)

Внимание - эта проверка имеет большой смысл, и если вы ее отключите, вы можете получить очень уродливые и очень невидимые ошибки.Это довольно опасно.Не делайте этого, пожалуйста.

Не используйте его, если не видите невидимых ошибок или не держите КАЖДУЮ линию под контролем

0 голосов
/ 31 мая 2018

Не пропущена фильтрация имени пользователя?Я думаю, что вы хотели что-то вроде:

SELECT users.user_id INTO user_id FROM users WHERE users.username = username;

Таким образом, значение users.user_id будет установлено в переменной user_id после фильтрации имени пользователя.

...