Oracle
 sql >> Base de données >  >> RDS >> Oracle

Détection de cycle avec factorisation récursive de sous-requêtes

À partir de la documentation sur CONNECT_BY_ISCYCLE :

Le CONNECT_BY_ISCYCLE la pseudo-colonne renvoie 1 si la ligne courante a un enfant qui est aussi son ancêtre

et cela sur CYCLE :

Une ligne est considérée comme formant un cycle si l'une de ses lignes ancêtre a les mêmes valeurs pour les colonnes du cycle.

Dans votre exemple, ligne 2 a un enfant qui est aussi son ancêtre, mais son id n'a pas encore été retourné.

En d'autres termes, CONNECT_BY_ISCYCLE vérifie les enfants (qui n'ont pas encore été retournés), tandis que CYCLE vérifie la ligne actuelle (qui est déjà retourné).

CONNECT BY est basé sur les lignes, tandis que CTE récursif sont basés sur des ensembles.

Notez que la documentation d'Oracle sur CYCLE mentionne une « ligne ancêtre ». Cependant, de manière générale, il n'y a pas de concept de "ligne ancêtre" dans un CTE récursif . C'est une opération basée sur un ensemble qui peut donner des résultats complètement hors de l'arbre. De manière générale, la partie ancre et la partie récursive peuvent même utiliser les différentes tables.

Depuis CTE récursif sont habituellement utilisé pour construire des arborescences hiérarchiques, Oracle a décidé d'ajouter une vérification de cycle. Mais en raison de la manière basée sur les ensembles, le CTE récursif , il est généralement impossible de dire si l'étape suivante générera un cycle ou non, car sans une définition claire de la condition de cycle "ligne ancêtre", il est impossible de définir non plus.

Pour effectuer l'étape "suivante", tout l'ensemble "courant" doit être disponible, mais pour générer chaque ligne de l'ensemble courant (qui inclut la colonne de cycle), nous avons juste besoin d'avoir les résultats de l'opération "suivante".

Ce n'est pas un problème si l'ensemble actuel se compose toujours d'une seule ligne (comme dans CONNECT BY ), mais c'est un problème si l'opération récursive est définie sur un ensemble dans son ensemble.

Je n'ai pas regardé Oracle 11 pour le moment, mais SQL Server implémente CTE récursif en masquant simplement un CONNECT BY derrière eux, ce qui nécessite de placer de nombreuses restrictions (qui interdisent toutes de fait toutes les opérations basées sur les ensembles).

PostgreSQL L'implémentation de , en revanche, est véritablement basée sur les ensembles :vous pouvez effectuer n'importe quelle opération avec la partie d'ancrage dans la partie récursive. Cependant, il n'a aucun moyen de détecter les cycles, car les cycles ne sont pas définis en premier lieu.

Comme mentionné précédemment, MySQL n'implémente pas CTE 's du tout (il n'implémente pas HASH JOIN ou MERGE JOIN s aussi, seulement les boucles imbriquées, alors ne soyez pas trop surpris).

Ironiquement, j'ai reçu une lettre aujourd'hui sur ce sujet précis, que je couvrirai dans mon blog.

Mise à jour :

CTE récursif est dans SQL Server ne sont pas plus que CONNECT BY déguisé. Voir cet article sur mon blog pour des détails choquants :

  • SQL Server :les CTE récursifs sont-ils vraiment basés sur des ensembles ?