PostgreSQL - 具有局部变量的函数 - 列引用不明确

时间:2018-05-30 21:03:32

标签: postgresql plpgsql postgresql-9.5

我已经看过了与我的主题相符的其他问题,但在我的情况下,我认为模糊性来自与列相同名称的变量。

以下是我要创建的函数的简化版本:

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,因为它将在函数的UPDATEDELETE操作中使用,但我不会将它作为参数传递,只有用户名。

经过一些阅读并且之前遇到了一些参数问题我也意识到我可以使用get_user_id.username但它只适用于参数,而不是局部变量(如果我使用变量查询失败,因为没有get_user_id的FROM-clause。

因此,我错过了在函数内部查询中使用变量的明显内容(不是那么明显)吗?

---编辑

道歉我过度简化了这个功能,当然还有第一个获取user_id的查询,而且该部分工作正常。

4 个答案:

答案 0 :(得分:3)

我为参数和变量添加前缀,以便它们不太可能与列名冲突:

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;

答案 1 :(得分:1)

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

  

有时修复a中的所有模糊引用是不切实际的   大量的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)

注意 - 这个检查很有意义,如果你禁用它,你可能会得到一些非常丑陋且非常不可见的错误。这非常危险。请不要这样做。

不要使用它,除非你看到不可见的错误或你控制每一行

答案 2 :(得分:1)

任何局部变量都可以通过块标签

进行限定
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

通常所有可能的冲突局部变量都有前缀 - 公共前缀是_

答案 3 :(得分:0)

是不是缺少用户名过滤?我想你想要的东西是:

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

这样,users.user_id的值将在用户名过滤后在user_id变量中设置。