代码之家  ›  专栏  ›  技术社区  ›  Moseleyi

postgresql-带有局部变量的函数-列引用不明确

  •  2
  • Moseleyi  · 技术社区  · 8 年前

    我已经看了一些与我的主题相匹配的其他问题,但在我的例子中,我相信这种模糊性来自于与列同名的变量。

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

    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 被视为对列的引用。

    我确实需要 用户ID 在一个局部变量中 UPDATE DELETE 在函数中进一步执行操作,但我不会将其作为参数传递,而只将其作为用户名传递。

    经过一些阅读和之前的一些参数问题,我也意识到我可以使用 get_user_id.username 但它只适用于参数,而不适用于局部变量(如果我将它与变量一起使用,则查询将失败,因为 get_user_id )

    因此,我是否遗漏了在函数内部的查询中使用变量的一些(不那么明显的)明显的东西?

    ---编辑

    抱歉,我把函数过于简单化了,当然有第一个查询可以获得用户id,而且该部分工作正常。

    4 回复  |  直到 8 年前
        1
  •  3
  •   Gordon Linoff    8 年前

    我给参数和变量加前缀,这样它们就不太可能与列名冲突:

    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;
    
        2
  •  2
  •   Pavel Stehule    8 年前

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

    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
  •  2
  •   Vao Tsun    8 年前

    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)
    

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

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

        4
  •  0
  •   Rafael Araújo    8 年前

    是否缺少用户名筛选?我想你想要的是:

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

    这样的话 users.user_id 将设置为 user_id 用户名筛选后的变量。