PostgreSQL
 sql >> Base de Dados >  >> RDS >> PostgreSQL

Consulta Postgresql ltree para encontrar o pai com a maioria dos filhos; excluindo raiz

Solução


Para encontrar o nó com mais filhos:
SELECT subpath(path, -1, 1), count(*) AS children
FROM   tbl
WHERE  path <> ''
GROUP  BY 1
ORDER  BY 2 DESC
LIMIT  1;

... e exclua os nós raiz:
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

Supondo que os nós raiz tenham um ltree vazio ('' ) como caminho. Pode ser NULL . Em seguida, use path IS NULL ...

O vencedor no seu exemplo é, na verdade, 2001 , com 5 filhos.

-> SQLfiddle

Como?


  • Use a função subpath(...) fornecido pelo o módulo adicional ltree .

  • Obtenha o último nó no caminho com um deslocamento negativo , que é o pai direto do elemento.

  • Conte com que frequência esse pai aparece, exclua nós raiz e pegue o restante com a contagem mais alta.

  • Use ltree2text() para extrair o valor de ltree .

  • Se vários nós tiverem o mesmo número de filhos, um arbitrário será escolhido no exemplo.

Caso de teste


Este é o trabalho que tive que fazer para chegar a um caso de teste útil (depois de cortar algum ruído):

Consulte SQLfiddle .

Em outras palavras:lembre-se de fornecer um caso de teste útil da próxima vez.

Colunas adicionais


Responda ao comentário.
Primeiro, expanda o caso de teste:
ALTER TABLE tbl ADD COLUMN postal_code text
              , ADD COLUMN whatever serial;
UPDATE tbl SET postal_code = (1230 + whatever)::text;

Dar uma olhada:
SELECT * FROM tbl;

Simplesmente JOIN resultado para o pai na tabela 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;