解決策
子が最も多いノードを見つけるには:
SELECT subpath(path, -1, 1), count(*) AS children
FROM tbl
WHERE path <> ''
GROUP BY 1
ORDER BY 2 DESC
LIMIT 1;
...そしてルートノードを除外します:
SELECT *
FROM (
SELECT ltree2text(subpath(path, -1, 1))::int AS tbl_id, count(*) AS children
FROM tbl
WHERE path <> ''
GROUP BY 1
) ct
LEFT JOIN (
SELECT tbl_id
FROM tbl
WHERE path = ''
) x USING (tbl_id)
WHERE x.tbl_id IS NULL
ORDER BY children DESC
LIMIT 1
ルートノードに空のltree
があると仮定します (''
)パスとして。 NULL
の可能性があります 。次に、path IS NULL
を使用します ...
あなたの例の勝者は実際には2001
です 、5人の子供がいます。
どのように?
-
関数
subpath(...)
追加モジュールltree
によって提供されます 。 -
最後のノードを取得します 負のオフセットのパス内 、要素の直接の親です。
-
その親が表示される頻度をカウントし、ルートノードを除外して、カウントが最も高い残りのノードを取得します。
-
ltree2text()
を使用しますltree
から値を抽出します 。 -
複数のノードに同じように最も多くの子がある場合、例では任意のノードが選択されます。
テストケース
これは、(ノイズをトリミングした後)有用なテストケースに到達するために私がしなければならなかった作業です:
SQLfiddle を参照してください。 。
言い換えれば、次回は有用なテストケースを提供することを忘れないでください。
追加の列
コメントへの回答。
まず、テストケースを展開します:
ALTER TABLE tbl ADD COLUMN postal_code text
, ADD COLUMN whatever serial;
UPDATE tbl SET postal_code = (1230 + whatever)::text;
ご覧ください:
SELECT * FROM tbl;
単にJOIN
ベーステーブルの親への結果:
SELECT ct.*, t.postal_code
FROM (
SELECT ltree2text(subpath(path, -1, 1))::int AS tbl_id, count(*) AS children
FROM tbl
WHERE path <> ''
GROUP BY 1
) ct
LEFT JOIN (
SELECT tbl_id
FROM tbl
WHERE path = ''
) x USING (tbl_id)
JOIN tbl t USING (tbl_id)
WHERE x.tbl_id IS NULL
ORDER BY children DESC
LIMIT 1;