我的目标是创建一个查询,我可以通过控制每个深度返回的项目的深度和数量来检索树,这个项目按排名降序排序,排名经常变化。
即
给我从节点id 4开始的树,最大深度为5(从该节点开始),每个级别最多5个子节点按排名降序排序。
所以我有一个树形结构:
CREATE TABLE thingtree
(
id uuid NOT NULL,
parent_id uuid,
text character varying(2048) NOT NULL,
rank integer NOT NULL DEFAULT 0,
CONSTRAINT thingtree_pkey PRIMARY KEY (id),
CONSTRAINT thingtree_parent_id_fkey FOREIGN KEY (parent_id)
REFERENCES thingtree (id) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION
)
我希望按ID选择一个节点,然后获取所有子节点,并在每个深度拉回一个可配置的记录限制,并按排名排序,这通常会发生变化。
所以我决定创建一些数据:
CREATE EXTENSION "uuid-ossp";
CREATE FUNCTION build_tree (parent_id uuid,max_depth integer,current_depth integer,max_direct_children integer) RETURNS boolean AS $$
DECLARE
new_id uuid := uuid_generate_v4();
BEGIN
IF current_depth >= max_depth THEN
RETURN 0;
END IF;
insert into thingtree VALUES (new_id, parent_id,'test',current_depth + 1);
FOR i IN 0..(max_direct_children - 1) LOOP
PERFORM build_tree(new_id,max_depth,current_depth + 1, max_direct_children);
END LOOP;
RETURN 0;
END;
$$ LANGUAGE plpgsql;
然后,我使用此函数生成一个深度为5的树,每个深度上有6个子项
select build_tree(NULL ,5, 0 ,6);
上述功能可能需要约20秒才能运行
接下来我尝试递归选择数据:
WITH RECURSIVE thingtrees AS (
SELECT tt.id,1::INT AS depth, tt.parent_id, tt.text, tt.rank FROM thingtree as tt WHERE id = '207f7c55-1c68-4f0e-9493-416b84b6a0a4'
UNION ALL
SELECT st.id, tts.depth + 1 AS depth, st.parent_id, st.text, st.rank
FROM
thingtrees as tts
JOIN
thingtree st
on (tts.id = st.parent_id)
WHERE tts.depth <= 5 order by st.rank
)
SELECT *
FROM thingtrees
现在深度很好,它知道不要超过5,但问题是我只想在我的树中每个级别的节点最多有5个直接子节点,但结果返回6(因为我不是限制它)。
问题是如果我从CTE限制递归联合:
WITH RECURSIVE thingtrees AS (
SELECT tt.id,1::INT AS depth, tt.parent_id, tt.text, tt.rank FROM thingtree as tt WHERE id = '207f7c55-1c68-4f0e-9493-416b84b6a0a4'
UNION ALL
(SELECT st.id, tts.depth + 1 AS depth, st.parent_id, st.text, st.rank
FROM
thingtrees as tts
JOIN
thingtree st
on (tts.id = st.parent_id)
WHERE tts.depth <= 5 order by st.rank limit 5)
)
SELECT *
FROM thingtrees
这里的问题是它只返回树的前5个子节点,而不是每个深度的5个子节点。