2014-06-19 28 views
1

我有一個查詢,我已經簡化了一點:在PGSQL重用變量查詢

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
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

+0

在PDO中,您只能使用一次參數,所以我必須多次通過1337。我沒有嘗試交叉連接,這可能是一個體面的方法 – MrGlass

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塊不能帶參數或返回的行集。所以這不是理想的,但它的工作原理。