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