具有十六进制整数常数和十进制整数的负整数异或会产生不同的结果吗?

问题描述 投票:0回答:2

我尝试创建表'MyTable'并添加具有小int类型的字段“ field1”。

然后我在字段1中添加负数-12289。

然后执行以下SQL查询:

select field1 ^ 0xcfff from MyTable

结果为零。

但是如果我用十六进制整数常量替换十六进制整数常量,如下所示:

select field1 ^ 53247 from MyTable

结果为-65536。

为什么?

唯一线索是https://docs.microsoft.com/en-us/sql/t-sql/data-types/int-bigint-smallint-and-tinyint-transact-sql?view=sql-server-ver15

大于2,147,483,647的整数常量将转换为十进制数据类型,而不是bigint数据类型。

但是0xcfff和53247都比2,147,483,647小得多。为什么它们会产生差异结果?

更新:

据我所知,这个问题的关键是我们可以将0xcfff强制转换为小整数,如下所示:

select cast(0xcfff as smallint)

但是我们不能将53247强制转换为小整数,以下行将导致溢出:

select cast(53247 as smallint)

这与C / C ++不同。在C / C ++中,两个强制类型转换都可以。

sql-server int hex decimal xor
2个回答
0
投票

这是由于您的数据长度。执行按位运算符时,应使用相同的字节长度:

1100 1111 1111 1111 <--  -12289 as smallint (word)
1100 1111 1111 1111 <--  CFFF (-12289) (word)
0000 0000 0000 0000 <--  XOR result = 0 (word)

1111 1111 1111 1111 1100 1111 1111 1111 <--  -12289 as int (double word)
0000 0000 0000 0000 1100 1111 1111 1111 <--  53247 (0000CFFF) (double word)
1111 1111 1111 1111 0000 0000 0000 0000 <--  XOR result = -65536 (double word)

您可以尝试更改长度:

select cast(-12289 as int) ^ 0x00cfff, -12289 ^ cast(0x00cfff as int)

0
投票

您在这里缺少的鲜为人知的位是Data Type Precedence。这是检查方法:

declare @t table (
    Id smallint not null
);

insert into @t (Id)
select -12289;

select sq.*,
    sql_variant_property(sq.XBin, 'BaseType') as [BinType],
    sql_variant_property(sq.XDec, 'BaseType') as [DecType]
from (
    select t.Id,
        t.Id ^ 0xcfff as [XBin],
        t.Id ^ 53247 as [XDec]
    from @t t
) sq;

二进制文字0xcfff占用2个字节,因此可以隐式转换为列本身具有的smallint类型。但是,十进制文字被解释为int(不是因为它需要两个以上的字节,而是因为2 ^ 32-1下的SQL Server always interprets整数文字具有此数据类型,而所有更大的interpreted都将作为decimal)。这意味着现在必须将该列隐式转换为优先级高于intsmallint,并且其符号在转换期间得以保留。

© www.soinside.com 2019 - 2024. All rights reserved.