Прошу прощения за смутное название. Я не мог придумать, как лучше подвести итог проблемы. У меня есть иерархическая таблица (например, ID int, ParentID int
), и мне нужно создать поддерево для ID
. Это тривиально делается с помощью рекурсивного CTE. Сложность состоит в том, что для каждого узла мне нужно вычислить работающее побитовое ИЛИ набора соответствующих значений, а затем побитовое ИЛИ, которое приводит к тому же значению для родительского узла. Это означает, что каждый узел наследует битовую маску своего родителя и может устанавливать свои собственные дополнительные биты. Я могу вычислить это значение в элементе анкера КТОС с использованием OUTER APPLY
и методика упоминается в ранее вопрос Я спросил. К сожалению, я не могу вычислить его таким же образом в рекурсивной части 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_
EDIT
Если это помогает осмыслить проблему: иерархия очень похожа на структуру каталогов, а битовые маски похожи на разрешения, которые наследуются от родительских папок.
Пример данных
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)
Для @ID
1 я ожидаю, что запрос вернется:
+----+----------+---------+
| ID | ParentID | BitMask |
+----+----------+---------+
| 1 | NULL | 1 |
| 2 | 1 | 7 |
| 3 | 1 | 57 |
+----+----------+---------+