web-dev-qa-db-ja.com

再帰CTEで親の子を数える

このクエリを使用して、親のコメントを検索しますid

WITH RECURSIVE cte (id, content, path, parent_id, depth)  AS (
    SELECT  id,
        content,
        array[id] AS path,
        parent_id,
        1 AS depth
    FROM    comment
    WHERE   id = 1

    UNION ALL

    SELECT  comment.id,
        comment.content,
        cte.path || comment.id,
        comment.parent_id,
        cte.depth + 1 AS depth
    FROM    comment
    JOIN cte ON comment.parent_id = cte.id
    WHERE depth < 3
    )
    SELECT id, content, path, parent_id, depth FROM cte
ORDER BY path LIMIT 200;

深さを3に制限していることを除いて、それはうまく機能します。現在の行にさらに多くの子があるかどうかを確認するにはどうすればよいですか。 「あとX回ロード」。

これについて最善の方法は何ですか?

this fiddle では、id 4と5には子供がいるので、それらを数えます。

2
Mike

allのすべての子を数えるには、最後の要素への各パスをたどる方法はありません。その後、残りを数えながらshow行をある深さまで表示できます。

WITH RECURSIVE cte AS (
   SELECT id, parent_id, content, array[id] AS path
   FROM   comment
   WHERE  id = 1

   UNION ALL
   SELECT c.id, c.parent_id, c.content, cte.path || c.id
   FROM   comment c
   JOIN   cte ON c.parent_id = cte.id
   )
SELECT DISTINCT ON (path[1:2])
       id, parent_id, content, path
     , count(*) OVER (PARTITION BY path[1:2]) - 1 AS children
FROM   cte
ORDER  BY path[1:2], path <> path[1:2]
LIMIT  200;  -- arbitrary limit, unrelated to the question

SQLフィドル

path[1:2]は、1番目から2番目の要素までの配列スライスです。 マニュアルの詳細。

これは深さ2で機能します。深さ3で同じようにするには、すべての1:21:3で置き換えます。

主な機能は、パスの最初のn個の要素で「グループ化」することです。この関連質問で説明されている手法を適用します。

最後のORDER BYpath <> path[1:2]は、グループのルート要素(パス全体が先頭の要素と等しい)にのみ当てはまるブール結果を生成し、FALSEは前にソートしますTRUE。代わりに単にpathを使用することもできますが、どちらの方がパフォーマンスが良いかわかりません。

4