J'ai le tableau suivant:
;WITH ChildParent AS ( SELECT a.id, a.name, a.isinedit, a.parent_id, a.isdeleted FROM dbo.table WHERE isdeleted = 0 AND isinedit = 0 UNION ALL SELECT a.id, a.name, a.isinedit, a.parent_id, a.isdeleted FROM dbo.table a INNER JOIN ChildParent cp ON a.parent_id = cp.id WHERE a.isdeleted = 0 AND a.isinedit = 0 ) SELECT id, name, parent_id, isinedit, isdeleted FROM ChildParent
Ce que je dois obtenir est une requête SELECT qui ne retournera que les lignes qui ont ISDELETED 0 et ISINEDIT 0 et dont les parents ou grands-parents sont également 0 p>
J'ai actuellement:
ID NAME PARENT_ID ISDELETED ISINEDIT 1 JJ NULL 1 0 2 AR 1 0 0 3 PR 2 0 0 4 DR NULL 0 1
Mais pour une raison quelconque, il renvoie des lignes doubles
3 Réponses :
Vous devez ajouter le même prédicat isdeleted = 0 AND isinedit = 0
à la source INNER JOIN childParent CP
.
... mais si vous faites cela vous faites votre requête CTE très fastidieuse et si vous devez répéter la même chose encore et encore, il y a probablement une meilleure façon de le faire.
... et il y en a! Une requête SELECT
peut avoir plusieurs expressions CTE:
; WITH filtered AS ( SELECT a.id, a.name, a.parent_id, FROM dbo.Table WHERE IsDeleted = 0 AND IsInEdit = 0 ) WITH cte AS ( SELECT a.id, a.name, a.parent_id FROM filtered UNION ALL SELECT a.id, a.name, a.parent_id FROM filtered INNER JOIN cte ON a.parent_id = cte.id ) SELECT * FROM cte ORDER BY id
Je pense que c'est un peu plus compliqué que vous ne le pensez. Si je comprends bien votre question, vous devez d'abord parcourir toute la hiérarchie des parents de chaque nœud, et ensuite vérifier si un parent ne respecte pas les règles (vous pouvez l'optimiser un peu en arrêtant après le premier parent non conforme est satisfait).
Vous devez également garder une trace du nœud d'origine, afin de pouvoir filtrer correctement dans la requête externe (ce qui évite les doublons que vous obtenez actuellement).
Je formulerais votre requête comme suit:
with cte as ( select t.*, t.id original_id, 0 lvl, 1 is_ok from dbo.table t where isdeleted = 0 and isinedit = 0 union all select t.*, c.original_id, c.lvl + 1, case when t.isdeleted = 0 and t.isinedit = 0 then 1 else 0 end from dbo.table t inner join cte c on c.parent_id = t.id where c.is_ok = 1 ) select * from cte c where c.lvl = 0 and not exists ( select 1 from cte c1 where c1.original_id = c.original_id and c1.is_ok = 0 )
Notez que cette requête fonctionnera quel que soit le nombre de niveaux existant dans l'arborescence (si vous avez plus de 100 niveaux, vous devez ajouter option (maxrecursion 0)
à la fin de la requête.
Ces types de requêtes sont plus faciles si vous créez d'abord un ensemble de données propre dans un CTE. Il supprime les clauses de filtrage supplémentaires dans toutes les requêtes CTE.
Dans ce cas, retourne toutes les lignes non supprimées et non dans is edit. La prochaine étape serait d'obtenir vos données. Grand-parent INNER JOIN Parent INNER JOIN CHILD
;WITH GoodDataRows AS ( SELECT a.id, a.name, a.isinedit, a.parent_id, a.isdeleted FROM dbo.table WHERE isdeleted = 0 AND isinedit = 0 ) SELECT * FROM GoodDataRows gp INNER JOIN GoodDataRows p ON p.parent_id = gp.id INNER JOIN GoodDataRows c on c.parent_id = p.id
Je recommande de créer un
VIEW
qui n'affiche que les enregistrements valides, et de définir le CTE sur cetteVIEW
plutôt que sur la table de base. Vous pouvez également utiliser un CTE antérieur avec les mêmes critères de filtre btw.