sql >> Base de Datos >  >> RDS >> PostgreSQL

Consulta ltree de Postgresql para encontrar padres con la mayoría de los hijos; excluyendo la raíz

Solución

Para encontrar el nodo con más hijos:

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

... y excluir los nodos raíz:

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

Suponiendo que los nodos raíz tienen un ltree vacío ('' ) como camino. Podría ser NULL . Luego use path IS NULL ...

El ganador en tu ejemplo es en realidad 2001 , con 5 hijos.

-> SQLfiddle

¿Cómo?

  • Use la función subpath(...) proporcionada por el el módulo adicional ltree .

  • Obtener el último nodo en la ruta con un desplazamiento negativo , que es el padre directo del elemento.

  • Cuente con qué frecuencia aparece ese padre, excluya los nodos raíz y tome el restante con el conteo más alto.

  • Use ltree2text() para extraer el valor de ltree .

  • Si varios nodos tienen la misma cantidad de hijos, se elige uno arbitrario en el ejemplo.

Caso de prueba

Este es el trabajo que tuve que hacer para llegar a un caso de prueba útil (después de recortar algo de ruido):

Ver SQLfiddle .

En otras palabras:recuerde proporcionar un caso de prueba útil la próxima vez.

Columnas adicionales

Responda al comentario.
Primero, expanda el caso de prueba:

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

Echa un vistazo:

SELECT * FROM tbl;

Simplemente JOIN resultado al padre en la tabla 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;