我有一个如下所述的简单表格,其中可能存在父/子关系。这实际上是一个非常大的表,但这是一个公平的表示。没有“孙子”关系。
我需要将其转换为稍微不同的表格,该表格会根据某些输入值进行过滤。
declare @pc table ( myId char(1) not null, parentId char(1) );
insert into @pc (myId, parentId) values ('A', null)
insert into @pc (myId, parentId) values ('B', 'A')
insert into @pc (myId, parentId) values ('C', 'A')
insert into @pc (myId, parentId) values ('D', null)
insert into @pc (myId, parentId) values ('E', null)
insert into @pc (myId, parentId) values ('F', 'E')
insert into @pc (myId, parentId) values ('G', null)
insert into @pc (myId, parentId) values ('H', 'G')
insert into @pc (myId, parentId) values ('I', 'G')
insert into @pc (myId, parentId) values ('J', 'G')
insert into @pc (myId, parentId) values ('K', null)
-- This is the results I need
declare @target table ( myId char(1) not null, parentId char(1), hasFamily bit );
如果输入“A”,那么我需要三行:
A NULL 1
B A 1
C A 1
换句话说,我需要属于“家庭群体”的所有东西。
鉴于“B”我需要相同的输出,B的家庭组中的所有内容(恰好是A的):
A NULL 1
B A 1
C A 1
鉴于“D”,我只需要一行,因为没有人在D家庭中:
D NULL 0
鉴于null
,我需要整个表数据集,但是正确的行标记为“有家人”。
这是我的尝试,这在技术上是正确的,但是根据数据进行3次传递并不高效:
declare @testcase char(1) = 'B';
-- The inefficient method
INSERT INTO @target( myId,parentId )
SELECT pc.myId, pc.parentId
FROM @pc pc
WHERE(pc.myId = ISNULL(@testcase, pc.myId))
OR (pc.parentId =@testcase);
INSERT INTO @target( myId,parentId )
SELECT pc.myId, pc.parentId
FROM @pc pc
WHERE pc.myId IN ( SELECT parentId FROM @target )
AND pc.myId NOT IN ( SELECT myId FROM @target );
update t
set t.hasFamily = 1
from @target t
left outer join @target t2
on t.myId = t2.parentId
where t.parentId is not null or t2.myId is not null;
你能看到一个更好的方法来看待这个问题吗?
答案 0 :(得分:1)
一个计算子项的窗口函数,在每一行都可用,简化了所需的查询。您是如何选择部署它的。例如,您可以选择使用持久计算列或触发器。如果规模和性能是问题,那么您需要考虑索引并检查执行计划。
也许我没有看到你在这里展示的小型模型的复杂性,因此我的建议可能过于简单。
演示create table Table1 ( myId char(1) not null, parentId char(1) );
insert into Table1 (myId, parentId) values ('A', null);
insert into Table1 (myId, parentId) values ('B', 'A');
insert into Table1 (myId, parentId) values ('C', 'A');
insert into Table1 (myId, parentId) values ('D', null);
insert into Table1 (myId, parentId) values ('E', null);
insert into Table1 (myId, parentId) values ('F', 'E');
insert into Table1 (myId, parentId) values ('G', null);
insert into Table1 (myId, parentId) values ('H', 'G');
insert into Table1 (myId, parentId) values ('I', 'G');
insert into Table1 (myId, parentId) values ('J', 'G');
insert into Table1 (myId, parentId) values ('K', null);
create view too_simplistic as
select
myId
, parentId
, coalesce(parentId, myId) parent_flat
, case when count(*) over(partition by coalesce(parentId, myId))-1 = 0
then 0
else 1
end as hasFamily
from table1
;
查询1 :
declare @want char(1) = 'A'
select myId, parentId, hasFamily
from too_simplistic
where parent_flat = (select parent_flat from too_simplistic where MyId = @want)
or MyId = @want
<强> Results 强>:
| myId | parentId | hasFamily |
|------|----------|-----------|
| A | (null) | 1 |
| B | A | 1 |
| C | A | 1 |
查询2 :
declare @want char(1) = 'B'
select myId, parentId, hasFamily
from too_simplistic
where parent_flat = (select parent_flat from too_simplistic where MyId = @want)
or MyId = @want
<强> Results 强>:
| myId | parentId | hasFamily |
|------|----------|-----------|
| A | (null) | 1 |
| B | A | 1 |
| C | A | 1 |
查询3 :
declare @want char(1) = 'D'
select myId, parentId, hasFamily
from too_simplistic
where parent_flat = (select parent_flat from too_simplistic where MyId = @want)
or MyId = @want
<强> Results 强>:
| myId | parentId | hasFamily |
|------|----------|-----------|
| D | (null) | 0 |
查询4 :
select *
from too_simplistic
<强> Results 强>:
| myId | parentId | parent_flat | hasFamily |
|------|----------|-------------|-----------|
| A | (null) | A | 1 |
| B | A | A | 1 |
| C | A | A | 1 |
| D | (null) | D | 0 |
| E | (null) | E | 1 |
| F | E | E | 1 |
| G | (null) | G | 1 |
| H | G | G | 1 |
| I | G | G | 1 |
| J | G | G | 1 |
| K | (null) | K | 0 |
select d.*
, case when children = 0 then 0 else 1 end as hasFamily
from (
select *
, count(*) over(partition by coalesce(parentId, myId))-1 children
from @pc
) d
;