问题
I have a CMS system which has a sitemap table with a parent-child relationship and a content table. Sometimes I don't want to include content in queries if it's corresponding sitemap entry or any of its parents is disabled.
The basic table structure is:
tb_Sitemap: id, parent_id, enabled
tb_Content: id, sitemap_id
So I want to be able to add something to my queries like this:
SELECT * FROM tb_Content WHERE {tb_Sitemap.enabled and any or all parents are also enabled}
I know I need to use a CTE but I am unsure about how to add these to a WHERE clause or how to go about it.
I am guessing I need do something like, but not sure how to add to a WHERE clause:
;WITH cte (enabled)
AS
(
SELECT enabled FROM tb_Content WHERE id = tb_Content.sitemap_id
UNION ALL
SELECT CASE WHEN b.enabled != 1 THEN 0 ELSE a.enabled FROM tb_Sitemap a
INNER JOIN cte b ON a.parent_id = b.id
)
SELECT enabled FROM cte
Sample data:
tb_Sitemap
- id: 1, parent_id: null, enabled: 1
- id: 2, parent_id: 1, enabled: 1
- id: 3, parent_id: 2, enabled: 1
- id: 4, parent_id: 1, enabled: 0
- id: 5, parent_id: 4, enabled: 1
- id: 6, parent_id: 5, enabled: 1
tbl_Content
- sitemap_id: 3 (this would appear because sitemap_id:3 is enabled as is all of its parents)
- sitemap_id: 6 (this will not appear because although sitemap_id:6 is enabled, one of its parents is not)
回答1:
-- A little test data.
declare @tb_Sitemap as table ( id int, parent_id int null, enabled bit )
insert into @tb_Sitemap ( id, parent_id, enabled ) values
( 1, NULL, 1 ), ( 2, 1, 1 ), ( 3, 2, 1 ),
( 4, 1, 0 ), ( 5, 4, 1 ), ( 6, 5, 1 )
declare @tb_Content as table ( sitemap_id int )
insert into @tb_Content ( sitemap_id ) values ( 3 ), ( 6 )
-- Query the little beggars.
; with CTE as (
-- Start at the root(s).
select id, parent_id, enabled, enabled as summary_enabled
from @tb_Sitemap
where parent_id is NULL
union all
-- Add one generation at a time.
select S.id, s.parent_id, s.enabled, cast( case when s.enabled = 1 and CTE.summary_enabled = 1 then 1 else 0 end as bit )
from CTE inner join
@tb_Sitemap as S on S.parent_id = CTE.id
)
select *, case when summary_enabled = 1 and sitemap_id is not NULL then '< winner!' else '' end as include
from CTE left outer join
@tb_Content as C on C.sitemap_id = CTE.id
来源:https://stackoverflow.com/questions/9185281/recursive-query-to-check-that-all-parents-are-enabled