Rozwiązanie
Aby znaleźć węzeł z największą liczbą dzieci:
SELECT subpath(path, -1, 1), count(*) AS children
FROM tbl
WHERE path <> ''
GROUP BY 1
ORDER BY 2 DESC
LIMIT 1;
... i wyklucz węzły główne:
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
Zakładając, że węzły główne mają puste ltree
(''
) jako ścieżka. Może być NULL
. Następnie użyj path IS NULL
...
Zwycięzcą w twoim przykładzie jest w rzeczywistości 2001
, z pięciorgiem dzieci.
Jak?
-
Użyj funkcji
subpath(...)
dostarczony przez dodatkowy modułltree
. -
Pobierz ostatni węzeł na ścieżce z ujemnym przesunięciem , który jest bezpośrednim rodzicem elementu.
-
Policz, jak często pojawia się ten rodzic, wyklucz węzły główne i weź pozostały z największą liczbą.
-
Użyj
ltree2text()
aby wyodrębnić wartość zltree
. -
Jeśli wiele węzłów ma jednakowo najwięcej dzieci, w przykładzie wybierany jest dowolny.
Przypadek testowy
To jest praca, którą musiałem wykonać, aby dostać się do użytecznego przypadku testowego (po przycięciu trochę szumu):
Zobacz SQLfiddle .
Innymi słowy:pamiętaj, aby następnym razem dostarczyć przydatny przypadek testowy.
Dodatkowe kolumny
Odpowiedz na komentarz.
Najpierw rozwiń przypadek testowy:
ALTER TABLE tbl ADD COLUMN postal_code text
, ADD COLUMN whatever serial;
UPDATE tbl SET postal_code = (1230 + whatever)::text;
Zobacz:
SELECT * FROM tbl;
Po prostu JOIN
wynik do rodzica w tabeli bazowej:
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;