简化CTE查询

时间:2016-09-06 16:47:24

标签: sql sql-server common-table-expression

我有一个数据结构,其中各种数据元素可以相互关联。一条记录可以是许多子记录的父记录,但子记录只能有一个父记录。我正在查询这些记录和家庭的问题。看看它们是否都标记为过时,以便我可以删除它们。

为了解决这个问题,我写了一篇CTE,从最底层的儿童记录开始,然后在树上工作,记录状态,最后得到一个家庭'在顶级记录中的状态。

我遇到这个问题的一个问题是当一个记录有多个孩子时,我最终得到了顶级父母的多个记录。在某些情况下,一个子路径可能有资格删除,但另一个不符合。我无法想出一种在CTE中识别这一点的方法,最后得到一个子查询,在那里我计算了符合删除条件的路径数,但是只返回带有>的记录。 1'删除'路径和0不要删除'路径。

这是我的代码,包含示例数据

create table #demand (id int, [status] varchar(10))
create table #relation (parent int, child int)

insert into #demand values (1, 'active')
insert into #demand values (2, 'obsolete')
insert into #demand values (3, 'obsolete')
insert into #demand values (4, 'obsolete')
insert into #demand values (5, 'active')
insert into #demand values (6, 'obsolete')

insert into #relation values(2, 3)
insert into #relation values(2, 4)
insert into #relation values(4, 5)

--the CTE splitFamily traverses the split family records from bottom up, checking that each record is Obsolete. If any record is not
;with
splitFamily as (
    select 
        D.id, 
        DR.child,
        case when D.[status] = 'obsolete' then 'Y' else 'N' end as CanDelete
    from #demand D
    left outer join #relation DR on D.id = DR.parent
    where DR.child is null

    union all

    select
        D.id, 
        DR.child,
        case when D.[status] = 'obsolete' and splitFamily.CanDelete = 'Y' then 'Y' else 'N' end as CanDelete
    from
        splitFamily
    join #relation DR on splitFamily.id = DR.child
    join #demand D  on DR.parent = D.id
)
select id from (
    select parentLevel.id,
    sum(case when parentLevel.CanDelete = 'Y' then 1 else 0 end) as "Y",
    sum(case when parentLevel.CanDelete = 'N' then 1 else 0 end) as "N"
    from splitFamily parentLevel
    --The following join ensures we only return top level parent records to be deleted. 
    left join splitFamily children on parentLevel.id = children.child
    where children.id is null
    group by parentLevel.id
) as splits where Y > 0 and N = 0

drop table #demand
drop table #relation

此代码有效,并输出记录6作为唯一符合条件的删除记录。如果记录5更改为“过时”,则查询在结果中正确包含2。

我的问题是关于是否有更清晰,更清晰的方法来识别CTE中的那些分裂路径,以避免额外的子查询和路径的计数。对我来说,这会混淆代码的目的,并使得维护前进变得更加困难。

1 个答案:

答案 0 :(得分:0)

我最终将我的最终选择更改为以下内容。使用窗口函数,我能够避免混淆的求和,在我看来,选择现在更加清晰。 id函数确保如果每个select distinct id from ( select parentLevel.id, FIRST_VALUE(parentLevel.CanDelete) over(partition by parentLevel.DemandId order by parentLevel.CanDelete) as CanDelete from splitFamily parentLevel left join splitFamily children on parentLevel.id = children.child where children.id is null ) as splits where CanDelete = 'Y' 的任何行都有N,则返回'N'。

{{1}}