Aggregate bitwise-OR in a subquery

后端 未结 10 2024
醉酒成梦
醉酒成梦 2020-11-30 08:46

Given the following table:

CREATE TABLE BitValues ( n int )

Is it possible to compute the bitwise-OR of n for all rows with

10条回答
  •  半阙折子戏
    2020-11-30 09:01

    This is an alternative, without 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;
    

    Also consider a Group By example:

     -- 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
    

    The first example is meant to be slower than WITH. However when you use GroupBy with some other data, the queries are largely the same cost-wise.

    Another way to do this is

        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;
    

    It's a bit worse because of repetition in code, a bit more readable and similar in execution cost.

提交回复
热议问题