0

あいまいなタイトルで申し訳ありません。問題をどのように要約すればよいか、私には思いつきませんでした。階層テーブル (例: ID int, ParentID int) があり、 のサブツリーを生成する必要がありIDます。これは、再帰的な CTE を使用して簡単に実行できます。難しいのは、ノードごとに、一連の対応する値の実行中のビット単位の OR を計算し、その結果が親ノードの同じ値になるビット OR を計算する必要があることです。これは、すべてのノードが親のビットマスクを継承し、独自の追加ビットを設定できることを意味します。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)

1 の場合@ID、クエリは次のように返されると思います。

+----+----------+---------+
| | ID | 親 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 に答える