我的目标是创建一个查询,我可以通过控制在每个深度返回的项目的深度和数量,按排名降序排序,排名经常变化,从而检索树 .

给我从节点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个子节点 .