PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

Postgresql-ltree-Abfrage, um Eltern mit den meisten Kindern zu finden; ausgenommen Wurzel

Lösung

So finden Sie den Knoten mit den meisten Kindern:

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

... und Wurzelknoten ausschließen:

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

Angenommen, die Wurzelknoten haben einen leeren ltree ('' ) als Pfad. Könnte NULL sein . Verwenden Sie dann path IS NULL ...

Der Gewinner in Ihrem Beispiel ist eigentlich 2001 , mit 5 Kindern.

-> SQLfiddle

Wie?

  • Verwenden Sie die Funktion subpath(...) bereitgestellt vom dem zusätzlichen Modul ltree .

  • Holen Sie sich den letzten Knoten im Pfad mit einem negativen Offset , das das direkte übergeordnete Element des Elements ist.

  • Zählen Sie, wie oft dieser Elternknoten vorkommt, schließen Sie Wurzelknoten aus und nehmen Sie den verbleibenden Knoten mit der höchsten Anzahl.

  • Verwenden Sie ltree2text() um den Wert aus ltree zu extrahieren .

  • Wenn mehrere Knoten gleich viele Kinder haben, wird im Beispiel ein beliebiges gewählt.

Testfall

Dies ist die Arbeit, die ich tun musste, um zu einem nützlichen Testfall zu gelangen (nachdem ich etwas Rauschen getrimmt habe):

Siehe SQLfiddle .

Mit anderen Worten:Bitte denken Sie beim nächsten Mal daran, einen nützlichen Testfall bereitzustellen.

Zusätzliche Spalten

Antwort auf Kommentar.
Erweitern Sie zuerst den Testfall:

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

Schau mal:

SELECT * FROM tbl;

Einfach JOIN Ergebnis zum Elternteil in der Basistabelle:

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;