plpgsql cte参数化数组导致错误消息

时间:2013-07-24 23:07:51

标签: sql postgresql plpgsql postgresql-8.4

我将尝试向复杂的选择查询注入和数组数组

CREATE FUNCTION permission_cache_update(
  IN affected_user_list INT4[]
)
  RETURNS TABLE(user_id INT4, permission_id INT4)
AS
  $BODY$
  BEGIN
    RETURN QUERY
    WITH
    affected_user AS (
      SELECT unnest(affected_user_list) AS user_id
    ), 
    permission_summary AS
    (
      SELECT affected_user.user_id, role_permission.permission_id
      FROM user_role, role_permission, affected_user
      WHERE role_permission.role_id = user_role.role_id AND user_role.user_id = affected_user.user_id
      UNION
      SELECT affected_user.user_id, user_permission.permission_id
      FROM user_permission, affected_user
      WHERE user_permission.user_id = affected_user.user_id
    )
    SELECT user_id, permission_id
    FROM permission_summary
    GROUP BY user_id, permission_id;
  END;
  $BODY$
LANGUAGE plpgsql VOLATILE;

问题出在这一部分:

    affected_user AS (
      SELECT unnest(affected_user_list) AS user_id
    ), 

但我不知道如何解决它。错误信息毫无意义。

[42601] ERROR: syntax error at or near "$2"

我想使用user_id, permission_id对来更新包含相同值的权限缓存。因此,询问用户权限会更快,因为它们将被缓存在那里。我想使用db来存储和检查会话权限。我不知道这是否是明智的......

2 个答案:

答案 0 :(得分:3)

我从你之前的问题中得出你正在使用PostgreSQL 8.4 ,这已经过时了。
您需要在每个问题中提供此信息!

在函数标题中声明

RETURNS TABLE(user_id INT4, permission_id INT4)

{/ 1}}参数OUTuser_id 在PL / pgSQL的函数体中随处可见。为避免命名冲突,您需要对同名的列进行表限定。您的函数也无法与现代Postgres一起正常工作,因为最终permission_id中的引用将返回SELECT值:

NULL

Postgres 8.4有更多的问题和

的错误
SELECT user_id, permission_id

命名冲突对于旧版本是不可接受的。较新的版本解决了这个问题。

sql函数

您可以将 SQL函数大致简化的查询一起使用:

SELECT unnest(affected_user_list) AS user_id
  • 使用正确的连接语法。更容易阅读和维护。 我还简化了CREATE FUNCTION permission_cache_update(affected_user_list int[]) RETURNS TABLE(user_id int, permission_id int) AS $func$ WITH affected_user AS (SELECT unnest($1) AS user_id) SELECT a.user_id, r.permission_id FROM user_role u JOIN role_permission r USING (role_id) JOIN affected_user a USING (user_id) UNION SELECT a.user_id, p.permission_id FROM user_permission p JOIN affected_user a USING (user_id) $func$ LANGUAGE sql; ,这是品味和风格的问题。它更简单,更短,但需要明确的列名。因此,对于Postgres 8.4的plpgsql版本也不行,但在现代版本中有效。

  • 原始查询中包含USING的最终SELECT只是噪音。 GROUP BY(与UNION相对)已隐式删除重复项。

plpgsql函数

如果避免命名冲突,plpgsql版本也应该起作用:

UNION ALL

答案 1 :(得分:2)

您确定问题与您引用的部分有关吗?我刚刚创建了该函数的简化版本并且它可以工作。您尝试使用什么版本的Postgres?也许某些功能在您的版本中不起作用(我在9.2上测试过)。

我测试了什么:

DROP FUNCTION IF EXISTS permission_cache_update(int4[]);
CREATE FUNCTION permission_cache_update(
  IN affected_user_list INT4[]
)
  RETURNS TABLE(user_id INT4, user_id2 INT4)
AS
  $BODY$
  BEGIN
    RETURN QUERY
    WITH
    affected_user AS (
      SELECT unnest(affected_user_list) AS user_id
    ),
    foo as (select * from affected_user)
    select au.*, foo.*
    from affected_user au
    inner join foo using (user_id);
  END;
  $BODY$
LANGUAGE plpgsql VOLATILE;

select * from permission_cache_update(array[1,2,3]::int4[]);

 user_id | user_id2 
---------+----------
       1 |        1
       2 |        2
       3 |        3