Reputation: 9252
I have a query, which I have simplified a little to:
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;
This works, but I have to put in that id value (1337) several times. This isn't so bad in my abstract example, but gets really ugly with my more complex real world query & since I'm using PHP/PDO I have to pass in the same variable multiple times.
What I'm looking for is some trick to declare my variable once and then reuse it, like:
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;
But obviously that doesnt work.
Is there a way to declare a variable once in a pgsql query and reuse it?
Upvotes: 2
Views: 2047
Reputation: 324375
Unfortunately there is not a good way. Clodaldo has shown the only way that's really viable in plain SQL.
The other way, and what I generally do, is wrap it in a trivial SQL function.
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);
Unfortunately PostgreSQL doesn't have TEMPORARY
functions, and DO
blocks cannot take parameters or return a rowset. So it's not ideal, but it works.
Upvotes: 3
Reputation: 125214
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)
or do a cross join if the subquery is too ugly
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)
But if you are passing parameters from PHP then I don't see the problem of just placing the parameters holders in the place of 1337
Upvotes: 5