【问题标题】:SQL Server : select parent/children to nth degreeSQL Server:选择父/子到第 n 度
【发布时间】:2021-03-11 00:03:58
【问题描述】:

我正在尝试从两个表中选择单个父记录的每个可能的子记录。

表一包含当前所有者和父所有者的所有帐户 表二是保存父母和孩子之间关系的表。 到目前为止,我已经设法选择了主要的父母。

我想不通的是如何与子孙相处

以表结构为例:

表帐户:

accountId | name | last name | email | OwningBusiness

表关系:

BusinessUnit | unitname | ParentBusinessUnit

OwningBusiness <=> BusinessUnitId
OwningBusiness <=> parentGroupOwner

我的主要目标是选择以根为基础父级的整个树。 如何制定一个查询,从父组中获取所有帐户,然后检查谁是孩子,从孩子中选择所有帐户,并继续这样做,直到检查完所有可能的孩子/孙子?

编辑: 搜索应基于给定的 ParentBusinessUnit,并且应仅返回包含帐户表中所有列的帐户记录 示例数据:

OwningBusinessUnit                 ParentBusinessUnit
7C6A387E-4231                         113D3FDB-7B8E
A871C1DB-9B49                         7C6A387E-4231
99E668AC-E183                         113D3FDB-7B8E
61E240E0-5FDB                         964467C5-5EDB
DF12F932-60DB                         964467C5-5EDB
1A836362-883E                         CB52AEC3-9EA2
CDBF825B-51D6                         113D3FDB-7B8E
C7839193-51D6                         CDBF825B-51D6
F8831375-51D6                         CDBF825B-51D6
BEA96E00-7675                         113D3FDB-7B8E
556A4549-7675                         BEA96E00-7675
E4FD4238-A4F0                         E178822F-AF63
6CFE118A-62B0                         113D3FDB-7B8E

通过使用以下查询,我已创建交集以提供上述数据

select a.OwningBusinessUnit, bu.ParentBusinessUnit from Accounts a
inner join Relations bu on a.OwningBusinessUnit = bu.BusinessUnitId
group by bu.ParentBusinessUnit, a.OwningBusinessUnit

请求的结果: 提供 ParentBusinessUnit "113D3FDB-7B8E" 作为参数应该可以找到所有 帐户:“113D3FDB-7B8E”、“7C6A387E-4231”、“99E668AC-E183”、“CDBF825B-51D6”、“A871C1DB-9B49”等

编辑 2: 根据答案,我做了以下更改:

declare @root nvarchar(50) = '113D3FDB-7B8E';
with rcte as
(
  select 
    br.Name buName,
    br.BusinessUnit,
    br.ParentBusinessUnit,
    a.*
  from BusinessUnitBase br
  join AccountBase a on a.OwningBusinessUnit = br.BusinessUnit
  where br.ParentBusinessUnit = @root and br.IsDisabled = 0
union all
  select 
  r.*
  from rcte r
  join BusinessUnitBase br on br.ParentBusinessUnit = br.BusinessUnit
)
select 
    r.*
from rcte r
order by r.buName

发生的情况是返回的帐户仅适用于没有孙子的第一个孩子

【问题讨论】:

  • 请展示一些示例数据和您的预期输出
  • 两张表如何连接?
  • 2 个表已连接,稍后将添加一些示例数据

标签: sql sql-server database


【解决方案1】:

递归公用表表达式可以解决这个问题。

样本数据

create table Account
(
  AccountId int,
  Name nvarchar(10),
  OwningBusiness int
);

insert into Account (AccountId, Name, OwningBusiness) values
(1, 'Alfred', 100),
(2, 'Batman', 200);

create table BusinessRelation
(
  BusinessUnit int,
  ParentBusinessUnit int,
  Name nvarchar(20)
);

insert into BusinessRelation (BusinessUnit, ParentBusinessUnit, Name) values
(100, null, 'Alfred Ltd.'),
(110, 100 , 'Alfred Holdings'),
(120, 100 , 'Alfred Rent-A-Car'),
(111, 110 , 'Alfred Supplies'),
(200, null, 'Batman Corp.'),
(210, 200 , 'Batman Automotive');

解决方案

with rcte as
(
  select a.AccountId,
         a.Name as AccountName,
         br.Name as BusinessName,
         br.BusinessUnit,
         br.ParentBusinessUnit,
         convert(nvarchar(100), br.BusinessUnit) as Relation
  from Account a
  join BusinessRelation br
    on br.BusinessUnit = a.OwningBusiness
union all
  select r.AccountId,
         r.AccountName,
         br.Name,
         br.BusinessUnit,
         br.ParentBusinessUnit,
         convert(nvarchar(100), convert(nvarchar(10), r.Relation) + ' > ' + convert(nvarchar(10), br.BusinessUnit))
  from rcte r
  join BusinessRelation br
    on br.ParentBusinessUnit = r.BusinessUnit
)
select r.AccountId,
       r.AccountName,
       r.BusinessName,
       r.BusinessUnit,
       r.Relation
from rcte r
order by r.AccountId,
         r.BusinessUnit;

结果

AccountId  AccountName  BusinessName       BusinessUnit  Relation
---------  -----------  -----------------  ------------  ---------------
1          Alfred       Alfred Ltd.        100           100
1          Alfred       Alfred Holdings    110           100 > 110
1          Alfred       Alfred Supplies    111           100 > 110 > 111
1          Alfred       Alfred Rent-A-Car  120           100 > 120
2          Batman       Batman Corp.       200           200
2          Batman       Batman Automotive  210           200 > 210

Fiddle 了解实际情况。


更新

使用新的样本数据。

create table BusinessRelation
(
  BusinessUnit nvarchar(13),
  ParentBusinessUnit nvarchar(13)
);

insert into BusinessRelation (BusinessUnit, ParentBusinessUnit) values
('7C6A387E-4231', '113D3FDB-7B8E'),
('A871C1DB-9B49', '7C6A387E-4231'),
('99E668AC-E183', '113D3FDB-7B8E'),
('61E240E0-5FDB', '964467C5-5EDB'),
('DF12F932-60DB', '964467C5-5EDB'),
('1A836362-883E', 'CB52AEC3-9EA2'),
('CDBF825B-51D6', '113D3FDB-7B8E'),
('C7839193-51D6', 'CDBF825B-51D6'),
('F8831375-51D6', 'CDBF825B-51D6'),
('BEA96E00-7675', '113D3FDB-7B8E'),
('556A4549-7675', 'BEA96E00-7675'),
('E4FD4238-A4F0', 'E178822F-AF63'),
('6CFE118A-62B0', '113D3FDB-7B8E');

declare @root nvarchar(13) = '113D3FDB-7B8E';

with rcte as
(
  select br.BusinessUnit,
         br.ParentBusinessUnit,
         convert(nvarchar(100), @root + ' > ' + br.BusinessUnit) as Relation,
         1 as Lvl
  from BusinessRelation br
  where br.ParentBusinessUnit = @root
union all
  select br.BusinessUnit,
         br.ParentBusinessUnit,
         convert(nvarchar(100), r.Relation + ' > ' + br.BusinessUnit),
         r.Lvl + 1
  from rcte r
  join BusinessRelation br
    on br.ParentBusinessUnit = r.BusinessUnit
)
select @root as ParentBusinessUnit,
       r.BusinessUnit,
       r.Relation,
       r.Lvl
from rcte r
order by r.Relation;

结果:

ParentBusinessUnit  BusinessUnit   Relation                                       Lvl
------------------  -------------  ---------------------------------------------  ---
113D3FDB-7B8E       6CFE118A-62B0  113D3FDB-7B8E > 6CFE118A-62B0                  1
113D3FDB-7B8E       7C6A387E-4231  113D3FDB-7B8E > 7C6A387E-4231                  1
113D3FDB-7B8E       A871C1DB-9B49  113D3FDB-7B8E > 7C6A387E-4231 > A871C1DB-9B49  2
113D3FDB-7B8E       99E668AC-E183  113D3FDB-7B8E > 99E668AC-E183                  1
113D3FDB-7B8E       BEA96E00-7675  113D3FDB-7B8E > BEA96E00-7675                  1
113D3FDB-7B8E       556A4549-7675  113D3FDB-7B8E > BEA96E00-7675 > 556A4549-7675  2
113D3FDB-7B8E       CDBF825B-51D6  113D3FDB-7B8E > CDBF825B-51D6                  1
113D3FDB-7B8E       C7839193-51D6  113D3FDB-7B8E > CDBF825B-51D6 > C7839193-51D6  2
113D3FDB-7B8E       F8831375-51D6  113D3FDB-7B8E > CDBF825B-51D6 > F8831375-51D6  2

Updated fiddle.

【讨论】:

  • 感谢您的回答,如果我理解正确,这将遍历整个表格并检查所有记录的关系?
  • 没错。如果只想选择一种树结构,则在rctelike this 中添加where 子句。
  • @Mike.G,anwer 也更新了新的样本数据。
  • 我想我可能无法很好地解释自己想要的结果。我正在寻找的结果是树中的帐户,而不是关系,返回的帐户应该基于关系,但我在输出中不需要它们,或者我无法理解答案
  • 如果你不需要什么,那么do not select it?
猜你喜欢
  • 1970-01-01
  • 2013-07-13
  • 1970-01-01
  • 2016-12-13
  • 1970-01-01
  • 1970-01-01
  • 2011-03-11
  • 1970-01-01
相关资源
最近更新 更多