SQL 查询 parent child 没有关系
SQL query for parent child with no relationship
我需要有关我要创建的查询的帮助。例如,假设我有这个 table:
Description Level Is_Active
----------------------------------------------------
(1)Metallic industry products 1 1
(2)+ Various metal products 2 1
(3)++ Other metal products 3 1
(1)Rubber and plastic products 1 1
(2)+ Rubber products 2 1
(2)+ Other rubber products 2 1
(3)++ Other product types 3 1
其中级别指定关系。 table 中的记录被设置为再现树结构。我想要做的是一个查询,其中 selects 所有 parents 和 children 从这个 table 是活跃的。例如,如果金属工业产品的 Is_Active 列设置为 0,我不想显示它,它是 children(各种金属产品和其他金属产品)。
各种金属制品也一样,没激活的就不显示了,就是children。我尝试使用相同的 table 或使用 WITH 函数加入,但遗憾的是我找不到解决方案。
一个更具体的例子是这样的。金属工业产品变得不活跃。那么 select 结果应该是:
Description Level Is_Active
----------------------------------------------------
(1)Rubber and plastic products 1 1
(2)+ Rubber products 2 1
(2)+ Other rubber products 2 1
(3)++ Other product types 3 1
或者假设金属行业产品的 child 变为非活动状态。结果集应该是这样的:
Description Level Is_Active
----------------------------------------------------
(1)Metallic industry products 1 1
(1)Rubber and plastic products 1 1
(2)+ Rubber products 2 1
(2)+ Other rubber products 2 1
(3)++ Other product types 3 1
好吧,我已经试过了,它不是很漂亮,但看看你的想法。我使用 WHILE 循环而不是游标来最小化代码:
create table #ordered_products
(id int identity(1,1),
grouping int default 0,
Description varchar(128),
level int,
is_active bit);
insert into #ordered_products (Description, level, is_active)
select description, level, is_active from products;
-- All rows now have an order
declare @grouping int = 0;
declare @currentid int;
declare @found bit = 1;
declare @level int;
declare @base int;
set @currentid = (select min(id) from #ordered_products);
-- Go through all the rows setting a new group each time we hit level 1
while (@found = 1)
begin
set @level = (select level from #ordered_products where id = @currentid);
if (@level = 1)
begin
set @grouping = @grouping + 1
end
update #ordered_products set grouping = @grouping where id = @currentid
set @currentid = @currentid + 1;
set @found = (select 1 from #ordered_products where id = @currentid);
end
-- For each group, set the children to be inactive if the parent is
declare @maxgroup int = (select MAX(GROUPING) from #ordered_products);
declare @currentgroup int = 1;
while (@currentgroup <= @maxgroup)
begin
begin
set @base = (select MIN(id) from #ordered_products where is_active = 0 and grouping = @currentgroup);
if (@base > 0)
begin
update #ordered_products set is_active = 0 where grouping = @currentgroup and id > @base;
end
end
set @currentgroup = @currentgroup + 1;
end
-- Output
select * from #ordered_products where is_active = 1;
drop table #ordered_products;
我需要有关我要创建的查询的帮助。例如,假设我有这个 table:
Description Level Is_Active
----------------------------------------------------
(1)Metallic industry products 1 1
(2)+ Various metal products 2 1
(3)++ Other metal products 3 1
(1)Rubber and plastic products 1 1
(2)+ Rubber products 2 1
(2)+ Other rubber products 2 1
(3)++ Other product types 3 1
其中级别指定关系。 table 中的记录被设置为再现树结构。我想要做的是一个查询,其中 selects 所有 parents 和 children 从这个 table 是活跃的。例如,如果金属工业产品的 Is_Active 列设置为 0,我不想显示它,它是 children(各种金属产品和其他金属产品)。
各种金属制品也一样,没激活的就不显示了,就是children。我尝试使用相同的 table 或使用 WITH 函数加入,但遗憾的是我找不到解决方案。
一个更具体的例子是这样的。金属工业产品变得不活跃。那么 select 结果应该是:
Description Level Is_Active
----------------------------------------------------
(1)Rubber and plastic products 1 1
(2)+ Rubber products 2 1
(2)+ Other rubber products 2 1
(3)++ Other product types 3 1
或者假设金属行业产品的 child 变为非活动状态。结果集应该是这样的:
Description Level Is_Active
----------------------------------------------------
(1)Metallic industry products 1 1
(1)Rubber and plastic products 1 1
(2)+ Rubber products 2 1
(2)+ Other rubber products 2 1
(3)++ Other product types 3 1
好吧,我已经试过了,它不是很漂亮,但看看你的想法。我使用 WHILE 循环而不是游标来最小化代码:
create table #ordered_products
(id int identity(1,1),
grouping int default 0,
Description varchar(128),
level int,
is_active bit);
insert into #ordered_products (Description, level, is_active)
select description, level, is_active from products;
-- All rows now have an order
declare @grouping int = 0;
declare @currentid int;
declare @found bit = 1;
declare @level int;
declare @base int;
set @currentid = (select min(id) from #ordered_products);
-- Go through all the rows setting a new group each time we hit level 1
while (@found = 1)
begin
set @level = (select level from #ordered_products where id = @currentid);
if (@level = 1)
begin
set @grouping = @grouping + 1
end
update #ordered_products set grouping = @grouping where id = @currentid
set @currentid = @currentid + 1;
set @found = (select 1 from #ordered_products where id = @currentid);
end
-- For each group, set the children to be inactive if the parent is
declare @maxgroup int = (select MAX(GROUPING) from #ordered_products);
declare @currentgroup int = 1;
while (@currentgroup <= @maxgroup)
begin
begin
set @base = (select MIN(id) from #ordered_products where is_active = 0 and grouping = @currentgroup);
if (@base > 0)
begin
update #ordered_products set is_active = 0 where grouping = @currentgroup and id > @base;
end
end
set @currentgroup = @currentgroup + 1;
end
-- Output
select * from #ordered_products where is_active = 1;
drop table #ordered_products;