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
سؤال
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.