sql >> Database >  >> RDS >> PostgreSQL

Postgresql ltree-query om ouder te vinden met de meeste kinderen; exclusief root

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.

-> SQLfiddle

Hoe?

  • Gebruik de functie subpath(...) geleverd door de de aanvullende module ltree .

  • 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 uit ltree .

  • 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;



  1. Tijdig interval om gegevens uit db op te halen en te stoppen wanneer de gegevens aankomen

  2. Hoe maak je een 2D-array snel in PostgreSQL in een 1d-array?

  3. een UDF opslaan/opslaan

  4. PostgreSQL-fout:kon geen gegevens van de client ontvangen:er is een bewerking geprobeerd op iets dat geen socket is