首页 > 解决方案 > SQL Server 中按位运算的替代方法 >> 列中超过 62 位

问题描述

我的 SQL 上有递归脚本,例如:

  WITH recursive bits AS (
        SELECT 0 AS idx
        UNION ALL
        SELECT idx + 1 AS idx
        FROM bits
        WHERE bits.idx + 1 < 64)

select power(2,idx) , idx
from bits
WHERE (9223372036854775808 >> bits.idx & 1) = 1

但现在我需要将其转换为 SQL Server

我知道功能“权力”

    WITH  bits AS (
        SELECT 0 AS idx
        UNION ALL
        SELECT idx + 1 AS idx
        FROM bits
        WHERE bits.idx + 1 < 63
        
    )
select *
from bits
where floor(4611686018427387904/power( cast(2 as bigint) ,idx)) & 1 = 1

但我需要将 power(2,idx) 转换为 power(cast(2 as float), idx) ,其中 power> (2,62) - 之后运算符“&”不起作用。因为它仅适用于 int 类型。

标签: sqlsql-servertsql

解决方案


经过大量时间和尝试找到任何决定。最终版本 - 我们将为此行使用 varbinary(20)。

非常有帮助的主题: 如何在 SQL 函数 [DoBitsMatchFromBinary] 中的两个 varbinary 字段之间执行 AND BIT OPERATOR 但在那个版本中,我们有位从左到右的行。我有不同的位线:

预告:

大端

1 byte  7|6|5|4|3|2|1|0 
2 byte  15|14|13|12|11|10|9|8
3 byte  23|22|21|20|19|18|17|16
..
          

或小端

3 byte  23|22|21|20|19|18|17|16
2 byte  15|14|13|12|11|10|9|8
1 byte  7|6|5|4|3|2|1|0 
  ..
          
          

示例(mysql):

WITH RECURSIVE bits AS (
    SELECT 0 AS idx
    UNION ALL
    SELECT idx + 1 AS idx
    FROM bits
    WHERE bits.idx + 1 < 160)
SELECT *
FROM bits
WHERE (4611686018968453378 >> bits.idx & 1) = 1;
        

从右到左计算位 = 1 (1,8,22,29,62)

0x0201402000000040(大端)

0x4000000020400102(小端序)

CREATE FUNCTION [dbo].[DoBitsMatchFromBinaryFromBytes](@bitToCheck INT,@inputBinary VARBINARY(1024))
    RETURNS BIT
        AS
    BEGIN
 
        DECLARE @byte int = (@bitToCheck) / 8
        DECLARE @bit int = @bitToCheck - @byte * 8
        DECLARE @bytemask int = POWER(2, 8-@bit)
        SET @byte = @byte + 1
    
        RETURN floor(CONVERT(int, SUBSTRING(@inputBinary, @byte, 1), 2)/power( cast(2 as bigint),@bit)) & 1 
    END

它帮助我从“big endian”varbinary 正确的位数返回:

示例(mssql):

WITH  bits AS (
        SELECT 0 AS idx
        UNION ALL
        SELECT idx + 1 AS idx
        FROM bits
        WHERE bits.idx + 1 < 160)
    SELECT *
    FROM bits
    WHERE [dbo].[DoBitsMatchFromBinaryFromBytes](bits.idx,0x0201402000000040) = 1
    OPTION(MAXRECURSION 160);

如果有人可以改进这个版本,那就太好了。我希望它也能有所帮助。


推荐阅读