PostgreSQL
 sql >> Database >  >> RDS >> PostgreSQL

Query ltree di Postgresql per trovare il genitore con la maggior parte dei figli; esclusa la radice

Soluzione

Per trovare il nodo con più figli:

SELECT subpath(path, -1, 1), count(*) AS children
FROM   tbl
WHERE  path <> ''
GROUP  BY 1
ORDER  BY 2 DESC
LIMIT  1;

... ed escludi i nodi radice:

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

Supponendo che i nodi root abbiano un ltree vuoto ('' ) come percorso. Potrebbe essere NULL . Quindi usa path IS NULL ...

Il vincitore nel tuo esempio è in realtà 2001 , con 5 bambini.

-> SQLfiddle

Come?

  • Usa la funzione subpath(...) fornito da il modulo aggiuntivo ltree .

  • Ottieni l'ultimo nodo nel percorso con un offset negativo , che è il genitore diretto dell'elemento.

  • Conta la frequenza con cui appare quel genitore, escludi i nodi radice e prendi quello rimanente con il conteggio più alto.

  • Usa ltree2text() per estrarre il valore da ltree .

  • Se più nodi hanno lo stesso numero di figli, nell'esempio ne viene scelto uno arbitrario.

Caso di prova

Questo è il lavoro che dovevo fare per arrivare a un utile test case (dopo aver tagliato un po' di rumore):

Vedi SQLfiddle .

In altre parole:ricordati di fornire un utile caso di prova la prossima volta.

Colonne aggiuntive

Rispondi al commento.
Innanzitutto, espandi il test case:

ALTER TABLE tbl ADD COLUMN postal_code text
              , ADD COLUMN whatever serial;
UPDATE tbl SET postal_code = (1230 + whatever)::text;

Dai un'occhiata:

SELECT * FROM tbl;

Semplicemente JOIN risultato al genitore nella tabella di base:

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;