次の表があるとします。
CREATE TABLE BitValues ( n int )
サブクエリ内のn
すべての行のビットごとのORを計算することは可能ですか?たとえば、BitValuesに次の4つの行が含まれている場合:
+ --- + | n | + --- + | 1 | | 2 | | 4 | | 3 | + --- +
サブクエリが7を返すことを期待します。UDFを作成せずにこれをインラインで実行する方法はありますか?
次の表があるとします。
CREATE TABLE BitValues ( n int )
サブクエリ内のn
すべての行のビットごとのORを計算することは可能ですか?たとえば、BitValuesに次の4つの行が含まれている場合:
+ --- + | n | + --- + | 1 | | 2 | | 4 | | 3 | + --- +
サブクエリが7を返すことを期待します。UDFを作成せずにこれをインラインで実行する方法はありますか?
WITH Bits
AS ( SELECT 1 AS BitMask
UNION ALL
SELECT 2
UNION ALL
SELECT 4
UNION ALL
SELECT 8
UNION ALL
SELECT 16
)
SELECT SUM(DISTINCT BitMask)
FROM ( SELECT 1 AS n
UNION ALL
SELECT 2
UNION ALL
SELECT 3
UNION ALL
SELECT 4
UNION ALL
SELECT 5
UNION ALL
SELECT 6
) AS t
JOIN Bits ON t.n & Bits.BitMask > 0
この投稿はかなり古く、いくつかの有用な答えがありますが、これはかなりクレイジーで簡単な方法です...
Select
SUM(DISTINCT(n & 0x01)) +
SUM(DISTINCT(n & 0x02)) +
SUM(DISTINCT(n & 0x04))
as OrN
From BitValues
@AlexKuznetsovのソリューションと@Andomarのソリューションを組み合わせた単純なソリューション。
ビットマスクは再帰共通テーブル式によって生成されますが、@Andomarのソリューションよりも簡単な方法で生成されます。
次に、@AlexKuznetsovのソリューションと同じようにビットが合計されます。
この例では、16ビットのマスクが必要であると想定しているため、65536の制限があります。65536を2^Nに変更することにより、Nビットマスクを示すことができます。
WITH Bits AS
(
SELECT 1 BitMask
UNION ALL
SELECT 2 * BitMask FROM Bits WHERE BitMask < 65536 -- recursion
)
SELECT SUM(DISTINCT BitMask)
FROM
(SELECT 1 n
UNION ALL
SELECT 2 n
UNION ALL
SELECT 4 n
UNION ALL
SELECT 3 n) t
INNER JOIN Bits ON t.n & Bits.BitMask > 0
準備:
if object_id(N'tempdb..#t', N'U') is not null drop table #t;
create table #t ( n int );
insert into #t values (1), (2), (4), (3);
解決:
select max(n & 8) + max(n & 4) + max(n & 2) + max(n & 1) from #t;
|
変数を使用して、各行に対して「ビット単位または」( )を実行できます。
declare @t table (n int)
insert @t select 1 union select 2 union select 4
declare @i int
set @i = 0
select @i = @i | n
from @t
select @i
これは印刷し7
ます。selectでの変数の割り当ては、公式にはサポートされていないことに注意してください。
より厳密にはSQLの方法で、ビットごとに1行のテーブルを作成できます。32番目のビットは負の整数であるため、このテーブルには31行が含まれます。この例では、再帰CTEを使用してそのテーブルを作成します。
declare @t table (n int)
insert @t select 1 union select 2 union select 3
; with bits(nr, pow) as
(
select 1
, 1
union all
select nr + 1
, pow * 2
from bits
where nr <= 30
)
select sum(b.pow)
from bits b
where exists
(
select *
from @t t
where b.pow & t.n > 0
)
これは、ソーステーブルの任意のビットが設定されているビットを合計します。
COALESCE関数を使用してみましたが、機能します。例:
DECLARE @nOrTotal INT
SELECT @nOrTotal = COALESCE(@nOrTotal, 0) | nValor
FROM (SELECT 1 nValor
UNION
SELECT 2
UNION
SELECT 2) t
SELECT @nOrTotal
>> Result: 3
これは、WITHなしの代替手段です(hurrah !!!):
select sum(distinct isnull(n & BitMask, 0)) as resultvalue
from
(
SELECT 1 AS n
UNION ALL
SELECT 2
UNION ALL
SELECT 4
UNION ALL
SELECT 3
) t
INNER JOIN (SELECT 0 BitMask union all SELECT 1 union all SELECT 2 union all SELECT 4 union all SELECT 8 union all SELECT 16 union all SELECT 32 union all SELECT 64 union all SELECT 128 union all SELECT 256 union all SELECT 512 union all SELECT 1024 union all SELECT 2048 union all SELECT 4096 union all SELECT 8192 union all SELECT 16384 union all SELECT 32768 union all SELECT 65536) Bits -- = SELECT POWER(2, 16)
ON n & BitMask = BitMask;
GroupByの例も考えてみましょう。
-- Setup temp table to produce an example --
create table #BitValues
(
id int identity(1,1)
,value int
,groupby varchar(10)
)
insert into #BitValues
SELECT 1 AS value, 'apples'
UNION ALL
SELECT 2, 'apples'
UNION ALL
SELECT 4, 'apples'
UNION ALL
SELECT 3, 'apples'
-- Bit operation: --
select groupby, sum(distinct isnull(value & BitMask, 0)) as tempvalue
from #BitValues
INNER JOIN (SELECT 0 BitMask union all SELECT 1 union all SELECT 2 union all SELECT 4 union all SELECT 8 union all SELECT 16 union all SELECT 32 union all SELECT 64 union all SELECT 128 union all SELECT 256 union all SELECT 512 union all SELECT 1024 union all SELECT 2048 union all SELECT 4096 union all SELECT 8192 union all SELECT 16384 union all SELECT 32768 union all SELECT 65536) Bits -- = SELECT POWER(2, 16)
ON value & BitMask = BitMask
group by groupby
最初の例は、WITHよりも遅いことを意図しています。ただし、GroupByを他のデータと一緒に使用する場合、クエリはコスト的にほぼ同じです。
これを行う別の方法は
select
groupby
,max(case when n & 1 = 1 then 1 else 0 end)
+
max(case when n & 2 = 2 then 2 else 0 end)
+
max(case when n & 4 = 4 then 4 else 0 end)
+
max(case when n & 8 = 8 then 8 else 0 end)
+
max(case when n & 16 = 16 then 16 else 0 end)
+
max(case when n & 32 = 32 then 32 else 0 end)
+
max(case when n & 64 = 64 then 64 else 0 end)
+
max(case when n & 128 = 128 then 128 else 0 end)
+
max(case when n & 256 = 256 then 256 else 0 end)
+
max(case when n & 512 = 512 then 512 else 0 end)
+
max(case when n & 1024 = 1024 then 1024 else 0 end)
as NewDNC
from #BitValues
group by groupby;
コードの繰り返し、もう少し読みやすく、実行コストが似ているため、少し悪化します。
このようなものをお探しですか?
編集:他のコメントで述べたように、この回答は、BitValuesテーブルに2の累乗しか含まれないという仮定に基づいていました。質問の行の間を読み、インラインサブクエリの使用を推測しようとしました。
declare @BitValues table (
n int
)
declare @TestTable table (
id int identity,
name char(10),
BitMappedColumn int
)
insert into @BitValues (n)
select 1 union all select 2 union all select 4
insert into @TestTable
(name, BitMappedColumn)
select 'Joe', 5 union all select 'Bob', 8
select t.id, t.name, t.BitMappedColumn
from @TestTable t
inner join (select SUM(n) as BitMask from @BitValues) b
on t.BitMappedColumn & b.BitMask <> 0
私にとってはそれが最善の解決策です。
declare @res int
set @res=0
SELECT @res=@res|t.n
FROM ( SELECT 1 AS n
UNION ALL
SELECT 2
UNION ALL
SELECT 3
UNION ALL
SELECT 4
UNION ALL
SELECT 5
UNION ALL
SELECT 6
) AS t
読み取り可能で再利用可能なソリューションの最善の策は、ビット単位またはを実行するカスタムCLRAggregateを作成することです。このタイプの操作を作成するためのチュートリアルは、次の場所にあります: http: //msdn.microsoft.com/en-us/library/91e6taax (VS.80).aspx