Reputation: 1019
I have the following database model:
CREATE TABLE IF NOT EXISTS account (
name VARCHAR PRIMARY KEY,
parent INTEGER REFERENCES account(name) ON UPDATE CASCADE ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS permission (
name VARCHAR PRIMARY KEY
);
CREATE TABLE IF NOT EXISTS account_permission (
account VARCHAR NOT NULL REFERENCES account(name) ON UPDATE CASCADE ON DELETE CASCADE,
permission VARCHAR NOT NULL REFERENCES permission(name) ON UPDATE CASCADE ON DELETE CASCADE
);
DELETE FROM account;
DELETE FROM permission;
DELETE FROM account_permission;
INSERT INTO account(name) VALUES('a1');
INSERT INTO account(name) VALUES('a2');
INSERT INTO account(name, parent) VALUES('a3', 'a1');
INSERT INTO permission(name) VALUES('dummy');
INSERT INTO permission(name) VALUES('edit');
INSERT INTO permission(name) VALUES('delete');
INSERT INTO account_permission(account, permission) VALUES('a1', 'dummy');
INSERT INTO account_permission(account, permission) VALUES('a2', 'edit');
INSERT INTO account_permission(account, permission) VALUES('a3', 'delete');
What I want is a query which returns all accounts which have a permission and their permissions inherited from the parent account. In this case I expect a result like this:
account | permission
a1 | dummy
a2 | edit
a3 | dummy
a3 | delete
a1 and a2 is nothing special but I have no idea how to write the recursive query to include a3 with all parent permissions and its own permission. Any help is appreciated.
Upvotes: 1
Views: 1295
Reputation: 44951
P.s.
You should redesign the tables.
Account should have an ID and a NAME.
Permission should have an ID and a NAME.
Tables should be connected by IDs.
The iterative query returns tuples of accounts and ancestors (including self)
+---------+----------+
| account | ancestor |
+---------+----------+
| a1 | a1 |
+---------+----------+
| a2 | a2 |
+---------+----------+
| a3 | a1 |
+---------+----------+
| a3 | a3 |
+---------+----------+
The rest of the query is for matching each account`s ancestor with its permissions and removing redundancies.
with t
as
(
select name as account
,name as ancestor
from account
-- where name = ... /* for a specific account */
union all
select t.account
,a.parent as ancestor
from t
join account as a
on a.name = t.ancestor
where a.parent is not null
)
select distinct
t.account
,ap.permission
from t
join account_permission as ap
on ap.account = t.ancestor
order by t.account
,ap.permission
;
Upvotes: 1
Reputation:
You will need one more query, which fetch parent permission and that can be merged with union. Here it is
select * from account_permission
union
select a.name, ap.permission from account_permission ap, account a where a.parent = ap.account
Upvotes: 0