我需要找到二进制值中存在多少真位。
示例:
input: 0001101 output:3
input: 1111001 output:5
答案 0 :(得分:4)
虽然两个答案都有效,但两者都有问题。循环不是最优的并且会破坏该值。两种解决方案都不能在select语句中使用。
可能更好的解决方案是按以下方式屏蔽
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
这可以在select和update语句中使用。它也快一个数量级。 (在我的服务器上大约50次)
为了帮助您,您可能希望使用以下生成器代码
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
另外需要注意的是:如果使用bigint或超过32位,则必须按照以下方式进行投射
print ' + case when @Missing & cast(' + cast(@x as varchar) + ' as bigint) = ' + cast(@x as varchar) + ' then 1 else 0 end '
享受
答案 1 :(得分:3)
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
结果:
4
答案 2 :(得分:0)
我已经留下了各种调试选择。
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;
干杯 -
答案 3 :(得分:0)
您可以通过使用递归CTE将数据拆分为一个1字节值的表并计算该表的每个字节中所有正确的位来处理任意长度的二进制值...
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);
答案 4 :(得分:0)
这是我的函数,它返回任何长度的VARBINARY中的1位数字。
SELECT dbo.f_nColumnsUpdated(0x0001101); -- Returns 3
SELECT dbo.f_nColumnsUpdated(0x1111001); -- Returns 5
SELECT dbo.f_nColumnsUpdated(0x888888888888); -- Returns 8
SELECT dbo.f_nColumnsUpdated(0x0001FEFF0000); -- Returns 16
SELECT dbo.f_nColumnsUpdated(0x0001FEFF00000001FEFF0000); -- Returns 32
就我而言,我需要计算在Update触发器中修改的列数。我不想测试所有的UPDATE()与NOT UPDATE()列,因为列数可能会发生变化。
SET @NumRows INT = @@ROWCOUNT; -- Top of Trigger
-- [snipped]
IF @NumRows=1 --
AND UPDATE(EndTimeActual) --
AND UPDATE(EndTimeDate) --
AND UPDATE(EndTimeStatus) --
AND UPDATE(EndTimeValue) --
AND dbo.f_nColumnsUpdated(COLUMNS_UPDATED())=4
BEGIN
-- Do Process Here
END
CREATE FUNCTION dbo.f_nColumnsUpdated(
@Bits VARBINARY(MAX))
RETURNS INT
AS
BEGIN
--
-- Returns the # of Bits=1 in Arbitrary Length VARBINARY
--
DECLARE @Byte VARBINARY(1); -- 8 Bit Substring
DECLARE @Index INT = 1; -- Loop Index
DECLARE @nResult INT = 0; -- # of 1 Bits Discovered
WHILE @Index <= DATALENGTH(@Bits)
BEGIN
SET @Byte = SUBSTRING(@Bits, @Index, 1);
SET @nResult = @nResult
+ CASE WHEN @Byte & 1 = 1 THEN 1 ELSE 0 END
+ CASE WHEN @Byte & 2 = 2 THEN 1 ELSE 0 END
+ CASE WHEN @Byte & 4 = 4 THEN 1 ELSE 0 END
+ CASE WHEN @Byte & 8 = 8 THEN 1 ELSE 0 END
+ CASE WHEN @Byte & 16 = 16 THEN 1 ELSE 0 END
+ CASE WHEN @Byte & 32 = 32 THEN 1 ELSE 0 END
+ CASE WHEN @Byte & 64 = 64 THEN 1 ELSE 0 END
+ CASE WHEN @Byte & 128 = 128 THEN 1 ELSE 0 END;
SET @Index = @Index + 1;
END
RETURN @nResult;
END
GO