SQL将bigint拆分为两个int

时间:2015-10-13 16:35:14

标签: sql-server

我需要将一个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,它完美无缺。

2 个答案:

答案 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