Solusi
Untuk menemukan simpul dengan anak paling banyak:
SELECT subpath(path, -1, 1), count(*) AS children
FROM tbl
WHERE path <> ''
GROUP BY 1
ORDER BY 2 DESC
LIMIT 1;
... dan mengecualikan node root:
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
Dengan asumsi bahwa node root memiliki ltree
yang kosong (''
) sebagai jalan. Mungkin NULL
. Kemudian gunakan path IS NULL
...
Pemenang dalam contoh Anda sebenarnya adalah 2001
, dengan 5 anak.
Bagaimana?
-
Gunakan fungsi
subpath(...)
disediakan oleh modul tambahanltree
. -
Dapatkan simpul terakhir di jalur dengan offset negatif , yang merupakan induk langsung dari elemen.
-
Hitung seberapa sering induk itu muncul, kecualikan simpul akar dan ambil yang tersisa dengan jumlah tertinggi.
-
Gunakan
ltree2text()
untuk mengekstrak nilai dariltree
. -
Jika beberapa node memiliki anak paling banyak yang sama, maka yang dipilih adalah sembarang dalam contoh.
Kasus uji
Ini adalah pekerjaan yang harus saya lakukan untuk mendapatkan kasus uji yang berguna (setelah memangkas beberapa kebisingan):
Lihat SQLfiddle .
Dengan kata lain:harap ingat untuk memberikan kasus uji yang berguna lain kali.
Kolom tambahan
Jawaban untuk komentar.
Pertama, perluas kasus uji:
ALTER TABLE tbl ADD COLUMN postal_code text
, ADD COLUMN whatever serial;
UPDATE tbl SET postal_code = (1230 + whatever)::text;
Lihat:
SELECT * FROM tbl;
Cukup JOIN
hasil ke induk di tabel dasar:
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;