0

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

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对来更新包含相同值的权限缓存。因此询问用户权限会更快,因为它们将被缓存在那里。我想使用数据库来存储和检查会话权限。我不知道这是否是明智之举...

4

2 回答 2

3

I derive from your previous question that you are using PostgreSQL 8.4, which is pretty outdated by now.
You need to provide this information with every question!

In your function header you declare

RETURNS TABLE(user_id INT4, permission_id INT4)

The OUT parameters user_id and permission_id are visible everywhere in the function body in PL/pgSQL. To avoid naming conflicts you need to table-qualify columns of the same name. Your function would not work properly with modern Postgres either, since the reference in your final SELECT would return NULL values:

SELECT user_id, permission_id

Postgres 8.4 had more problems with that and errors out at

SELECT unnest(affected_user_list) AS user_id

The naming conflict is unacceptable to the old version. Newer versions have resolved this.

sql function

You can use this SQL function with a largely simplified query instead:

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;
  • Use proper join syntax. Much easier to read and maintain. I also simplified with USING, which is a matter of taste and style. It's simpler and shorter, but requires unambiguous column names. So that would not work in a plpgsql version for Postgres 8.4 either, but works in modern versions.

  • The final SELECT with the GROUP BY in your original query is just noise. UNION (as opposed to UNION ALL) already implicitly removes duplicates.

plpgsql function

If you avoid the naming conflicts, the plpgsql version should also work:

CREATE FUNCTION permission_cache_update(affected_user_list int[])
  RETURNS TABLE(user_id int, permission_id int) AS
$func$
BEGIN

RETURN QUERY
WITH affected_user AS (
   SELECT unnest(affected_user_list) AS u_id
   ) 
SELECT a.user_id, r.permission_id
FROM   user_role       u
JOIN   role_permission r USING (role_id)
JOIN   affected_user   a ON a.u_id = u.user_id

UNION
SELECT a.user_id, p.permission_id
FROM   user_permission p
JOIN   affected_user   a ON a.u_id = p.user_id;

END    
$func$  LANGUAGE plpgsql;
于 2013-07-25T02:15:02.347 回答
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
于 2013-07-24T23:25:20.040 回答