如果您只有一個水平繼承(如例子中),那麼你可以使用這樣的查詢:
WITH group_ids AS
(
SELECT group_id
FROM group_members
WHERE username LIKE 'Maciej'
)
SELECT group_name
FROM
(SELECT group_id FROM group_ids
UNION
SELECT DISTINCT parent_group_id
FROM groups_inheritance INNER JOIN group_ids USING(group_id)) g
INNER JOIN groups ON id = group_id;
結果:
group_name
------------------
People
Students
Football_players
(3 rows)
PL/pgSQL函數:
DROP FUNCTION IF EXISTS f(varchar(64));
CREATE FUNCTION f(username varchar(64))
RETURNS text[] AS $$
DECLARE
gId bigint;
pgId bigint;
gName text;
result text[] = '{}';
BEGIN
FOR gId IN SELECT group_id FROM group_members WHERE username LIKE username
LOOP
SELECT INTO gName group_name FROM groupS WHERE id = gId;
result := result || gName;
FOR pgId IN SELECT parent_group_id FROM groups_inheritance WHERE group_id = gId
LOOP
SELECT INTO gName group_name FROM groups WHERE id = pgId;
IF NOT (result @> ARRAY[gName]) THEN
result := result || gName;
END IF;
END LOOP;
END LOOP;
RETURN result;
END $$
LANGUAGE 'plpgsql';
結果:
SELECT f('Maciej');
f
------------------------------------
{Students,People,Football_players}
(1 row)
然而,對於嵌套家長團體,我認爲這應該遞歸是合適的。
編輯:
這裏是嵌套父組基於遞歸變體:
CREATE OR REPLACE FUNCTION f_recursive(gIdParam bigint, resultArrayParam bigint[])
RETURNS bigint[] AS $$
DECLARE
pgId bigint;
resultArray bigint[];
BEGIN
FOR pgId IN SELECT parent_group_id FROM groups_inheritance WHERE group_id = gIdParam
LOOP
IF NOT (resultArrayParam @> ARRAY[pgId]) THEN
resultArray := resultArray || pgId;
resultArray := resultArray || f_recursive(pgId, resultArray);
END IF;
END LOOP;
RETURN resultArray;
END $$
LANGUAGE 'plpgsql';
CREATE OR REPLACE FUNCTION f(usernameParam varchar(64))
RETURNS text[] AS $$
DECLARE
gId bigint;
resultArray bigint[];
BEGIN
FOR gId IN SELECT group_id FROM group_members WHERE username LIKE usernameParam
LOOP
resultArray := resultArray || gId;
resultArray := resultArray || f_recursive(gId, resultArray);
END LOOP;
RETURN array_agg(group_name)
FROM groups INNER JOIN (SELECT unnest(resultArray)) u ON unnest = id;
END $$
LANGUAGE 'plpgsql';
實施例插入件:
INSERT INTO groups (id, group_name) VALUES
(1, 'People'), (2, 'Workers'), (3, 'Programmers'),
(4, 'AI-Programmers'), (5, 'Administators'), (6, 'Managers');
INSERT INTO groups_inheritance (group_id, parent_group_id) VALUES
(2, 1), (3, 2), (4, 3), (5, 2), (6, 2);
INSERT INTO users (username, password, enabled) VALUES
('Maciej', '12345', true);
INSERT INTO group_members (id, username, group_id) VALUES
(1, 'Maciej', 4), (2, 'Maciej', 5);
結果:
SELECT f('Maciej');
f
-----------------------------------------------------------
{AI-Programmers,Programmers,Workers,People,Administators}
(1 row)
另一種方法是使用WITH query以及RECURSIVE
修飾符作爲顯示的@araqnid。
實際上,我決定接受它,因爲它更簡潔和適應性強。 –