0

我为模糊的标题道歉。我想不出如何最好地总结这个问题。我有一个分层表(例如ID int, ParentID int),需要为ID. 这可以通过递归 CTE 轻松完成。困难在于,对于每个节点,我需要计算一组相应值的运行按位或,然后对父节点计算结果与相同值的位或。这意味着每个节点都会继承其父节点的位掩码,并且可以设置自己的附加位。我可以使用我之前问过的问题OUTER APPLY中提到的技术来计算 CTE 的锚成员中的这个值。不幸的是,我不能在 CTE 的递归部分以相同的方式计算它,因为它在那里使用和聚合是不允许的。SUM

有没有办法重组它来做我想要的?

declare @ID int
set @ID = 1

;with _Bits_(RowNum, BitMask) as
(
  select
    1,
    1
  union all select
    RowNum + 1,
    BitMask * 2
  from
    _bits_
  where
    RowNum < 31
),
_Tree_ as
(
  select
    a.ID,
    a.ParentID,
    b.BitMask
  from
    Tree a
    outer apply
    (
      select
        sum(distinct y.BitMask) as BitMask
      from
        BitValues x
        inner join _Bits_ y
          on (x.Value & y.BitMask) <> 0
      where
        x.ID = a.ID
    ) b
  where
    a.ID = @ID
  union all select
    a.ID,
    a.ParentID,
    c.BitMask | b.BitMask
  from
    Tree a
    inner join _Tree_ b
      on b.ID = a.ParentID
    outer apply
    (
      select
        sum(distinct y.BitMask) as BitMask
      from
        BitValues x
        inner join _Bits_ y
          on (x.Value & y.BitMask) <> 0
      where
        x.ID = a.ID
    ) c
)
select * from _Tree_

编辑

如果它有助于概念化问题:层次结构很像目录结构,位掩码就像从父文件夹继承的权限。

示例数据

create table Tree (ID int primary key, ParentID int null foreign key references Tree (ID))

insert Tree values (1, null)
insert Tree values (2, 1)
insert Tree values (3, 1)

create table BitValues (ID int not null foreign key references Tree (ID), BitMask int not null)

insert BitValues values (1, 1)
insert BitValues values (2, 2)
insert BitValues values (2, 4)
insert BitValues values (3, 8)
insert BitValues values (3, 16)
insert BitValues values (3, 32)

对于@ID1,我希望查询返回:

+----+----------+---------+
| 身份证 | 家长 ID | 位掩码 |
+----+----------+---------+
| 1 | 空 | 1 |
| 2 | 1 | 7 |
| 3 | 1 | 57 |
+----+----------+---------+
4

2 回答 2

0
declare @ID int;
set @ID = 1;

with extrarows as
(
   select t.id, null as parent, v.BitMask as total
   from tree t
   join BitValues v on t.id = v.id
   where t.id = @ID

   union all 

   select t.id, r.id, v.BitMask | r.total
   from extrarows r
   join Tree t on r.id = t.parentid
   join BitValues v on t.id = v.id
)
select id, parent, 
  MAX(total & 1) +
  MAX(total & 2) +
  MAX(total & 4) +
  MAX(total & 8) +
  MAX(total & 16) +
  MAX(total & 32) +
  MAX(total & 128) +
  MAX(total & 256) +
  MAX(total & 512) +
  MAX(total & 1024) +
  MAX(total & 2048)  -- more if you want em.
     as BitMask 
from extrarows   
group by id, parent

一些注意事项:

  • 我假设传入的@id 是树的“根”。(如果这不符合您的需要,请随意爬上树以查找根的起始位掩码。)

  • 虽然对位求和MAX确实有效,但对于许多记录上的大位串可能不具有性能。我不知道你有多少位,但它少于 16 位左右应该没问题 - 想听听你的发现。

  • 为了提高性能切换到自定义 C# 聚合。

于 2011-04-29T00:23:43.507 回答
0

对霍根的回答稍作改进(IMO):

declare @ID int;
set @ID = 1;

with _Bits_(RowNum, BitMask) as
(
  select
    1,
    1
  union all select
    RowNum + 1,
    BitMask * 2
  from
    _bits_
  where
    RowNum < 31
),
extrarows as
(
   select t.id, null as parent, v.BitMask as total
   from tree t
   join BitValues v on t.id = v.id
   where t.id = @ID

   union all 

   select t.id, r.id, v.BitMask | r.total
   from extrarows r
   join Tree t on r.id = t.parentid
   join BitValues v on t.id = v.id
)
select a.id, a.parent, sum(distinct y.BitMask) as BitMask
from extrarows a
  inner join _Bits_ y
    on (a.total & y.BitMask) <> 0  
group by a.id, a.parent
于 2011-04-29T16:41:41.203 回答