sql >> Database teknologi >  >> RDS >> Oracle

Cyklusdetektion med rekursiv subquery factoring

Fra dokumentation på CONNECT_BY_ISCYCLE :

CONNECT_BY_ISCYCLE pseudokolonne returnerer 1 hvis den aktuelle række har et barn, som også er dens forfader

og det på CYCLE :

En række anses for at danne en cyklus, hvis en af ​​dens forfaderrækker har de samme værdier for cykluskolonnerne.

I dit eksempel, række 2 har et barn, som også er dets forfader, men dets id er ikke returneret endnu.

Med andre ord, CONNECT_BY_ISCYCLE tjekker børnene (som endnu ikke skal returneres), mens CYCLE kontrollerer den aktuelle række (som allerede er returneret).

CONNECT BY er rækkebaseret, mens rekursiv CTE 's er sæt-baserede.

Bemærk, at Oracles dokumentation om CYCLE nævner en "forfaderrække". Men generelt set er der ikke noget begreb om en "forfaderrække" i en rekursiv CTE . Det er en sæt-baseret operation, som kan give resultater helt ud af træet. Generelt kan ankerdelen og den rekursive del endda bruge de forskellige tabeller.

Siden rekursiv CTE 's er normalt bruges til at bygge hierarkitræer, Oracle besluttede at tilføje et cyklustjek. Men på grund af den sæt-baserede måde den rekursive CTE 's fungerer, er det generelt umuligt at sige, om det næste trin vil generere en cyklus eller ej, for uden en klar definition af "forfaderrækken" kan cyklusbetingelsen heller ikke defineres.

For at udføre det "næste" trin skal hele det "aktuelle" sæt være tilgængeligt, men for at generere hver række i det aktuelle sæt (som inkluderer cykluskolonnen) skal vi blot have resultaterne af den "næste" operation.

Det er ikke et problem, hvis det aktuelle sæt altid består af en enkelt række (som i CONNECT BY ), men det er et problem, hvis den rekursive operation defineres på et sæt som en helhed.

Undersøgte ikke Oracle 11 endnu, men SQL Server implementerer rekursiv CTE ved blot at skjule en CONNECT BY bag dem, hvilket kræver, at der placeres adskillige restriktioner (som alle reelt forbyder alle sæt-baserede operationer).

PostgreSQL 's implementering er på den anden side virkelig set-baseret:du kan udføre enhver operation med ankerdelen i den rekursive del. Det har dog ingen midler til at detektere cyklusser, fordi cyklusser ikke er defineret i første omgang.

Som nævnt før, MySQL implementerer ikke CTE 's overhovedet (den implementerer ikke HASH JOIN 's eller MERGE JOIN s også, kun de indlejrede løkker, så bliv ikke overrasket meget).

Ironisk nok modtog jeg et brev i dag om netop dette emne, som jeg vil dække i min blog.

Opdatering:

Rekursiv CTE er i SQL Server er ikke mere end CONNECT BY i forklædning. Se denne artikel i min blog for chokerende detaljer:

  • SQL-server:er de rekursive CTE'er virkelig set-baserede?


  1. Få årets dag fra en dato i SQL Server (T-SQL)

  2. SQL Server på Linux

  3. Flere rækker til én kommasepareret værdi i SQL Server

  4. ORA-12514 fejl efter genstart af serveren