Oplossing
Om het knooppunt met de meeste kinderen te vinden:
SELECT subpath(path, -1, 1), count(*) AS children
FROM tbl
WHERE path <> ''
GROUP BY 1
ORDER BY 2 DESC
LIMIT 1;
... en sluit hoofdknooppunten uit:
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
Ervan uitgaande dat root-knooppunten een lege ltree
. hebben (''
) als pad. Mogelijk NULL
. Gebruik dan path IS NULL
...
De winnaar in jouw voorbeeld is eigenlijk 2001
, met 5 kinderen.
Hoe?
-
Gebruik de functie
subpath(...)
geleverd door de de aanvullende moduleltree
. -
Haal het laatste knooppunt op in het pad met een negatieve offset , wat de directe ouder van het element is.
-
Tel hoe vaak die ouder verschijnt, sluit rootknooppunten uit en neem de resterende met het hoogste aantal.
-
Gebruik
ltree2text()
om de waarde te extraheren uitltree
. -
Als meerdere knooppunten evenveel kinderen hebben, wordt in het voorbeeld een willekeurige gekozen.
Testcase
Dit is het werk dat ik moest doen om tot een bruikbare testcase te komen (na wat ruis te hebben bijgesneden):
Zie SQLfiddle .
Met andere woorden:vergeet niet om de volgende keer een bruikbare testcase mee te sturen.
Extra kolommen
Antwoord op commentaar.
Breid eerst de testcase uit:
ALTER TABLE tbl ADD COLUMN postal_code text
, ADD COLUMN whatever serial;
UPDATE tbl SET postal_code = (1230 + whatever)::text;
Kijk eens:
SELECT * FROM tbl;
Gewoon JOIN
resultaat naar de ouder in de basistabel:
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;