T-SQL隐式转换/重载解析如何工作?

时间:2016-01-28 09:27:32

标签: sql-server tsql overload-resolution

我一直在玩T-SQL试图理解隐式转换和重载解析规则,但不知何故它似乎有点奇怪......

背景:

基本上后者告诉你abs将对int,float,decimal等起作用。那么让我们看看它是如何工作的:

declare @foo2 sql_variant;
set @foo2 = abs(4);
select sql_variant_property(@foo2, 'BaseType')

-- result: int. OK, apparently we have an int overload. As expected.

declare @foo2 sql_variant;
set @foo2 = abs(cast(4.0 as float));
select sql_variant_property(@foo2, 'BaseType')

-- result: float. OK, apparently we have a float overload. As expected.

现在,根据隐式类型转换表,我们可以隐式转换内容。我们将通过将varbinary转换为int来检查这一点,这应该根据类型优先规则进行:

declare @foo varbinary(4);
set @foo = cast(4 as varbinary(4));
select @foo + 2;

-- result: int. OK, as expected.

从这个结果我希望以下内容也能正常工作:

declare @foo varbinary(4);
set @foo = cast(4 as varbinary(4));
select abs(@foo);
-- result: error: Operand type clash: varbinary is incompatible with float

东西我在这里不明白(问题):

  • 为什么隐式转换会选择'abs'的'float'重载?这只是一个随机过载吗?或者可能是优先级列表中最高的重载(恰好是'浮动')?
  • 为什么不从varbinary应用隐式转换 - >诠释?毕竟,这是完全有效的转换。

2 个答案:

答案 0 :(得分:1)

来自MSDN for Abs:

Arguments

numeric_expression

    Is an expression of the exact numeric or approximate numeric data type category.

我猜调用Abs(varbinary)会尝试将varbinary转换为精确数字或近似数值数据类型。

Float位于这些类型的数据类型优先级的顶部,所以我猜是有问题。

用我的逻辑更新

declare @foo varbinary(4);

声明一个varbinary变量。

set @foo = cast( 4 as varbinary(4));

通过执行从int到varbinary的显式转换来设置此变量值,这是完全可行的。

select sql_variant_property(@foo, 'BaseType')

这表明该变量的类型为varbinary。

select abs(@foo);

尝试在varbinary上运行abs。 错误消息很明确:

Operand type clash: varbinary is incompatible with float

所以我的猜测是abs试图将varbinary隐式转换为数据类型优先级中的第一个,用于精确数字或近似数值数据类型,即float。

根据CAST and CONVERT图表,此转化失败。

答案 1 :(得分:0)

我希望我做对了!评论赞赏。

您已经找到了MSDN页面的转换和优先级,所以让我们将您的示例分开。

declare @foo varbinary(4);
set @foo = cast(4 as varbinary(4));

现在,foo是什么类型的?

SELECT SQL_VARIANT_PROPERTY(@foo,'BaseType')

--------
varbinary

到目前为止这么好。但是@foo中有什么?

SELECT @foo
----------
0x00000004

现在,ABS()接受numeric - 浮点数:

enter image description here

4.00相比,4看起来像什么?我们试试吧:

SELECT  CONVERT(VARBINARY(MAX), 4.00) ,CONVERT(VARBINARY(MAX), 4);
------------------   -----------------------
0x0302000190010000   0x00000004

请参阅4.00的内部表示与4不同?它存储精度,比例和值,而你的'var in varbinary'不是。

这就是转换失败的原因。 ABS()接受numeric,您的'错误格式'varbinary无法强制转换为numeric,因为它不是一个,它是其他代表 - 我们知道它代表一个int但是SQL Server没有。

如果要将一个浮点数添加到varbinary的“内部”的int中,则必须执行类似

的操作
select CONVERT(INT, @foo) + 2.0

回到你的例子:

declare @foo varbinary(max);
set @foo = cast(4.00 as varbinary(max));
SELECT ABS(@foo+2.0)
----------
6.0

4.00以正确的内部格式转换为varbinary,并通过numeric电话愉快地强制转换为ABS()。快乐的日子。