SQL 服务器 Convert() 更改数据?

SQL Server Convert() changing data?

为什么会这样?

在下面的示例中,当我使用 ISNULL 比较空白 int 和空白 varchar 时,它们彼此相等。 当相同的逻辑被 convert 包装时,它们彼此不相等。

DECLARE @myint int
DECLARE @mychar VARCHAR(200)

SET @myint = null
SET @mychar = NULL

SELECT CASE when CONVERT(VARCHAR(40),iSNULL(@myint,'')) = CONVERT(VARCHAR(40),ISNULL(@mychar,'')) THEN 1 ELSE 0 END AS 'poop'

SELECT CASE when iSNULL(@myint,'') =ISNULL(@mychar,'') THEN 1 ELSE 0 END AS 'poop'`

这是一个问题的原因是因为我正在创建带有多个附加字段的散列键。我最近将一个字段的数据类型从 varchar 更改为 int(该字段只存储一个 int),现在当该字段为 null 时,生成的哈希键不同,因为 Convert 函数以某种方式将数据视为不同。

如果您还打印出较小表达式的结果,这将很有启发:

DECLARE @myint int
DECLARE @mychar VARCHAR(200)

SET @myint = null
SET @mychar = NULL

SELECT CASE when CONVERT(VARCHAR(40),iSNULL(@myint,'')) = CONVERT(VARCHAR(40),ISNULL(@mychar,'')) THEN 1 ELSE 0 END AS 'poop',
CONVERT(VARCHAR(40),iSNULL(@myint,'')),
CONVERT(VARCHAR(40),ISNULL(@mychar,''))

SELECT CASE when iSNULL(@myint,'') =ISNULL(@mychar,'') THEN 1 ELSE 0 END AS 'poop',
iSNULL(@myint,''),
ISNULL(@mychar,'')

您应该能够看到,即使在 ISNULL 检查之后,您最终也会将 @myint 替换为 0@mychar 一个空字符串。为什么?因为 ISNULL 总是 returns 与其第一个参数相同类型的数据,对于 @myIntint。并且 int 不能存储空字符串。当空字符串转换为 int 时,它被解释为 0.

这也是您第二次比较中发生的情况 - 我们将 intvarchar 进行比较,并且由于 int 具有更高的优先级,这就是转换发生的方向in 等他们比较相等。

但在第一种情况下,您实际上是在强制数据转换发生在另一个方向。而0转成varchar不会变成空串。

原因都与 Data type precedence (Transact-SQL) 有关,这是 SQL 服务器的文档部分。

对于ISNULL,使用的数据类型是第一个值的数据类型。所以对于ISNULL(@int,''),如果@int的值为NULL,那么就会使用''的值。然而,''varchar,并且具有 int 更低的 数据类型优先级;因此它被转换为 int'' 作为一个整数是 0。因此,(再次假设 @int 的值为 NULLISNULL(@int,'') = 0 的计算结果为真。

但是,如果 @int 是一个(奇怪的)varchar,那么 ISNULL(@int,'') 将 return '',而不是 0 .因此,您可以立即看到因数据类型而导致的行为差异。 但是请注意,即使 @intvarcharISNULL(@int,'') = 0 的计算结果仍为真,因为在解析表达式时数据类型优先级将再次应用。

不同的函数处理数据类型优先级的方式不同。因此,例如 COALESCE 在函数中使用最高数据类型优先级。因此 COALESCE('a',1) 会尝试 return 和 int (并失败)。另一方面,ISNULL('a',1) 将 return 变成 varchar(1),因为这是第一个参数的数据类型。

这是因为隐式转换。当您在 ISNULL 中包装一个 int 并告诉它 return 一个空字符串时,会将该空字符串隐式转换为 int。当空字符串转换为 int 时,它变为 0。

这就是我的意思。

DECLARE @myint int
SET @myint = null
select iSNULL(@myint,'')