在PGSQL查询中重用变量

时间:2014-06-19 19:44:02

标签: php postgresql pdo

我有一个查询,我已经简化了一点:

WITH users AS (
    SELECT member_id FROM group_members AS gm 
        JOIN groups AS g on gm.group_id = g.id 
        WHERE g.id = 1337 OR g.parents @> ARRAY[1337]
    )
UPDATE access SET revoked = TRUE 
    WHERE user_id IN (SELECT member_id FROM users)

RETURNING user_id;

这有效,但我必须多次输入id值(1337)。在我的抽象例子中,这并不是那么糟糕,但是对于我更复杂的现实世界查询而言却变得非常丑陋。因为我使用PHP / PDO,所以我必须多次传入相同的变量。

我正在寻找的是一次声明我的变量然后重复使用它的技巧,例如:

DECLARE gid = 1337
WITH users AS (
    SELECT member_id FROM group_members AS gm 
        JOIN groups AS g on gm.group_id = g.id 
        WHERE g.id = gid OR g.parents @> ARRAY[gid]
    )
UPDATE access SET revoked = TRUE 
    WHERE user_id IN (SELECT member_id FROM users)

RETURNING user_id;

但显然这不起作用。

有没有办法在pgsql查询中声明一次变量并重用它?

2 个答案:

答案 0 :(得分:2)

with gid as (
    select 1337 as gid
), users as (
    select member_id
    from
        group_members as gm 
        join
        groups as g on gm.group_id = g.id 
    where
        g.id = (select gid from gid) or
        g.parents @> array[(select gid from gid)]
)
update access
set revoked = true 
where user_id in (select member_id from users)

如果子查询太丑,则进行交叉连接

with gid as (
    select 1337 as gid
), users as (
    select member_id
    from
        group_members as gm 
        join
        groups as g on gm.group_id = g.id
        cross join
        gid
    where g.id = gid or g.parents @> array[gid]
)
update access
set revoked = true 
where user_id in (select member_id from users)

但是如果你从PHP传递参数,那么我没有看到只是将参数持有者放在1337

的位置的问题

答案 1 :(得分:2)

不幸的是,没有良好的方式。 Clodaldo已经展示了在纯SQL中真正可行的唯一方法。

另一种方式,以及我通常所做的,是将它包装在一个简单的SQL函数中。

CREATE OR REPLACE FUNCTION do_whatever(gid integer) RETURNS SETOF integer AS $$
WITH users AS (
    SELECT member_id FROM group_members AS gm 
        JOIN groups AS g on gm.group_id = g.id 
        WHERE g.id = $1 OR g.parents @> ARRAY[$1]
    )
UPDATE access SET revoked = TRUE 
    WHERE user_id IN (SELECT member_id FROM users)
RETURNING user_id;
$$ LANGUAGE sql;

SELECT * FROM do_whatever(1337);

不幸的是,PostgreSQL没有TEMPORARY个函数,而DO块不能获取参数或返回行集。所以它不理想,但它有效。