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
VIEWqui n'affiche que les enregistrements valides, et de définir le CTE sur cetteVIEWplutôt que sur la table de base. Vous pouvez également utiliser un CTE antérieur avec les mêmes critères de filtre btw.