سؤال

I need to find how many true bit exists in my binary value.

example:

input: 0001101    output:3
input: 1111001    output:5
هل كانت مفيدة؟

المحلول 2

DECLARE @BinaryVariable2 VARBINARY(10);

SET @BinaryVariable2 = 60; -- binary value is 111100

DECLARE @counter int  = 0

WHILE @BinaryVariable2 > 0 
  SELECT @counter +=@BinaryVariable2 % 2,  @BinaryVariable2 /= 2

SELECT @counter

Result:

4

نصائح أخرى

While both answers work, both have issues. A loop is not optimal and destructs the value. Both solutions can not be used in a select statement.

Possible better solution is by masking together as follows

select @counter = 0 
+ case when @BinaryVariable2 & 1 = 1 then 1 else 0 end 
+ case when @BinaryVariable2 & 2 = 2 then 1 else 0 end 
+ case when @BinaryVariable2 & 4 = 4 then 1 else 0 end 
+ case when @BinaryVariable2 & 8 = 8 then 1 else 0 end 
+ case when @BinaryVariable2 & 16 = 16 then 1 else 0 end 
+ case when @BinaryVariable2 & 32 = 32 then 1 else 0 end 
+ case when @BinaryVariable2 & 64 = 64 then 1 else 0 end 
+ case when @BinaryVariable2 & 128 = 128 then 1 else 0 end 
+ case when @BinaryVariable2 & 256 = 256 then 1 else 0 end 
+ case when @BinaryVariable2 & 512 = 512 then 1 else 0 end 

This can be used in a select and update statement. It is also an order of magnitude faster. (on my server about 50 times)

To help you might want to use the following generator code

declare @x int = 1, @c int = 0
print ' @counter = 0 '  /*CHANGE field/parameter name */
while @c < 10  /* change to how many bits you want to see */
begin
print ' + case when @BinaryVariable2 & ' + cast(@x as varchar) + ' = ' + cast(@x as varchar) + ' then 1 else 0 end '   /* CHANGE the variable/field name */
select @x *=2, @c +=1
end 

Also as further note: if you use a bigint or go beyond 32 bits it is necessary to cast like follows

print ' + case when @Missing & cast(' + cast(@x as varchar) + ' as bigint) = ' + cast(@x as varchar) + ' then 1 else 0 end '

Enjoy

I've left various debug selects in.

begin

    declare @bin as varbinary(20);
    declare @bitsSet as int;

    set @bitsSet = 0;
    set @bin = convert(varbinary(20), 876876876876);

    declare @i as int;

    set @i = 0

    select LEN(@bin), 'Len';

    while @i < LEN(@bin)
    begin
      declare @bit as varbinary(1);
      set @bit = SUBSTRING(@bin, @i, 1);
      select @bit, 'Bit';

      declare @power as int
      set @power = 0;

      while @power < 8
      begin
        declare @powerOf2 as int;
        set @powerOf2 = POWER(2,  @power);
        if @powerOf2 <> 0
            set @bitsSet = @bitsSet + (@bit & @powerOf2) / @powerOf2; -- edited to add the divisor
        select @power, @powerOf2;

        set @power = @power + 1;
      end;

      select @bitsSet;
      set @i = @i + 1;
    end;
    select @bitsSet, 'End'
end;

Cheers -

You can handle an arbitrary length binary value by using a recursive CTE to split the data into a table of 1-byte values and counting all of the bits that are true in each byte of that table...

DECLARE @data Varbinary(MAX) = Convert(Varbinary(MAX), N'We can count bits of very large varbinary values without a loop or number table if you like...');


WITH each ( byte, pos ) AS (
    SELECT Substring(@data, Len(@data), 1), Len(@data)-1 WHERE Len(@data) > 0
    UNION ALL
    SELECT Substring(@data, pos, 1), pos-1 FROM each WHERE pos > 0
    )
SELECT Count(*) AS [True Bits]
FROM each
CROSS JOIN (VALUES (1),(2),(4),(8), (16),(32),(64),(128)) [bit](flag)
WHERE each.byte & [bit].flag = [bit].flag
OPTION (MAXRECURSION 0);

From SQL Server 2022 you can just use SELECT BIT_COUNT(input)

expression_value can be

Any integer or binary expression that isn't a large object (LOB).

For integer expressions the result can depend on the datatype. e.g. -1 as smallint has a binary representation of 1111111111111111 (two's complement) and will have more bits set for int datatype.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top