我需要将一个bigint字符串的两半的unsigned int对应存储在DB中的两个单独字段中,以便与第三方解决方案兼容。
我已经在这里查看了解决方案,它似乎运行良好,除了它经常返回负数的事实。我认为这是因为SQL期望它被签名的无符号数据,但我在那里猜测......
SQL - safely downcast BIGINT to INT
DECLARE @BigintDataLimitIn BIGINT = 8589934590;
DECLARE @RightHalf INT, @LeftHalf INT;
WITH v AS (SELECT CAST(@BigintDataLimitIn AS varbinary) AS bin)
SELECT
@LeftHalf = SUBSTRING(bin, 1, 4),
@RightHalf = SUBSTRING(bin, 5, 4)
FROM v;
SELECT @LeftHalf, @RightHalf
----------------------------------------
(LeftHalf) (RightHalf)
1 -2
所以我的问题是为什么右半输出有时会返回一个不正确的负值,我该如何解决这个问题呢?它总是正确的?
对于使用.NET执行此操作的某些输入数字,我看到了相同的奇怪结果。
Dim original As Int64 = 8589934590
Dim rightHalfUnSigned As UInt32 = CType(original And &H7FFFFFFF, UInt32)
Console.writeline(rightHalfUnSigned)
Output: 2147483646
我不太了解这些功能的基础知识,足以知道为什么输入数字为8589934590,但对于8589934595,它完美无缺。
答案 0 :(得分:1)
SQL Server将您的字节视为有符号整数。二进制数据仍然是正确的。
大约一半的时间表示数字中最低有效字节的字节将落在四字节signed int的负范围内。你有相同的情况,负值被拆分:有时下半部分是正面的。
你可能会这样想。在分成两个值之后,你现在有了两个符号位(前导位),而不仅仅是你开始使用的那个。
这可能有助于取回您希望看到的无符号值:
cast(0x00000000 + cast(@RightHalf as binary(4)) as bigint)
如下所示,保留bigint类型可能更容易:
@LeftHalf = @BigintDataLimitIn / 4294967296
@RightHalf = @BigintDataLimitIn % 4294967296
答案 1 :(得分:1)
完美,功能强大,代码行数少于原始代码。很棒的答案。
DECLARE @BigintDataLimitIn BIGINT = 8589934590;
DECLARE @RightHalf INT, @LeftHalf INT;
WITH v AS (SELECT CAST(@BigintDataLimitIn AS varbinary) AS bin)
SELECT
@LeftHalf = SUBSTRING(bin, 1, 4)
FROM v;
SELECT @LeftHalf as LeftHalf, @BigintDataLimitIn % 4294967296 as RightHalf
-----------------------------
LeftHalf RightHalf
1 4294967294