sql >> Databáze >  >> RDS >> PostgreSQL

Postgresql rekurzivní vlastní připojení

Toto je klasické použití jednoduchého rekurzivního společného tabulkového výrazu (WITH RECURSIVE ), dostupné v PostgreSQL 8.4 a novějších.

Demonstrováno zde:http://sqlfiddle.com/#!12/78e15/9

Vzhledem k ukázkovým datům jako SQL:

CREATE TABLE Table1
    ("ID1" text, "ID2" text)
;

INSERT INTO Table1
    ("ID1", "ID2")
VALUES
    ('vc1', 'vc2'),
    ('vc2', 'vc3'),
    ('vc3', 'vc4'),
    ('vc4', 'rc7')
;

Můžete napsat:

WITH RECURSIVE chain(from_id, to_id) AS (
  SELECT NULL, 'vc2'
  UNION
  SELECT c.to_id, t."ID2"
  FROM chain c
  LEFT OUTER JOIN Table1 t ON (t."ID1" = to_id)
  WHERE c.to_id IS NOT NULL
)
SELECT from_id FROM chain WHERE to_id IS NULL;

To znamená, že iterativně prochází řetězcem a přidává každý řádek do chain tabulka jako od-a-ukazatele. Když narazí na řádek, pro který odkaz 'to' neexistuje, přidá pro tento řádek nulový odkaz 'to'. Další iterace si všimne, že odkaz 'to' je nulový a vytvoří nulové řádky, což způsobí ukončení iterace.

Vnější dotaz poté vybere řádky, které byly určeny jako konec řetězce tím, že mají neexistující to_id.

Zorientovat se v rekurzivních CTE vyžaduje trochu úsilí. Klíčové věci, kterým je třeba porozumět, jsou:

  • Začínají výstupem počátečního dotazu, který opakovaně spojují s výstupem „rekurzivní části“ (dotaz za UNION nebo UNION ALL ), dokud rekurzivní část nepřidá žádné řádky. To zastaví iteraci.

  • Ve skutečnosti nejsou rekurzivní, spíše iterativní, i když jsou dobré pro věci, na které byste mohli použít rekurzi.

Takže v podstatě vytváříte stůl ve smyčce. Nemůžete odstraňovat řádky ani je měnit, pouze přidávat nové, takže obecně potřebujete vnější dotaz, který filtruje výsledky, abyste získali požadované řádky výsledků. Často budete přidávat další sloupce obsahující přechodná data, která používáte ke sledování stavu iterace, řízení stop-conditions atd.

Může pomoci podívat se na nefiltrovaný výsledek. Pokud nahradím závěrečný souhrnný dotaz jednoduchým řetězcem SELECT * FROM chain Vidím tabulku, která byla vygenerována:

 from_id | to_id 
---------+-------
         | vc2
 vc2     | vc3
 vc3     | vc4
 vc4     | rc7
 rc7     | 
(5 rows)

První řádek je ručně přidaný řádek počátečního bodu, kde zadáte, co chcete vyhledat – v tomto případě to bylo vc2 . Každý následující řádek byl přidán UNION ed rekurzivní termín, který provede LEFT OUTER JOIN na předchozí výsledek a vrátí novou sadu řádků, které spárují předchozí to_id (nyní v from_id sloupec) na další to_id . Pokud LEFT OUTER JOIN neodpovídá potom to_id bude null, což způsobí, že další vyvolání vrátí nyní řádky a ukončí iteraci.

Protože tento dotaz se nepokouší přidat pouze poslední řádek pokaždé, je to vlastně opakování slušného kusu práce při každé iteraci. Abyste tomu zabránili, museli byste použít přístup podobný Gordonovi, ale navíc při skenování vstupní tabulky filtrovat předchozí pole hloubky, takže jste spojili pouze nejnovější řádek. V praxi to obvykle není nutné, ale může to být problém u velmi velkých souborů dat nebo tam, kde nemůžete vytvořit vhodné indexy.

Více se můžete dozvědět v dokumentaci PostgreSQL na CTE.



  1. Příkaz PRINT v T-SQL

  2. Jak zjistit, kdy byla tabulka Oracle naposledy aktualizována

  3. Přístup pomocí Microsoft SQL Server – import velkých datových sad pomocí SSIS

  4. Získejte jméno vlastníka DB v PostgreSql