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

Sql server T-SQL隐式转换/重载解析是如何工作的?,sql-server,tsql,overload-resolution,Sql Server,Tsql,Overload Resolution,我一直在玩弄T-SQL,试图理解隐式转换和重载解析规则,但不知何故,它似乎有点奇怪 背景: 数据类型转换: 数据类型优先级: Abs: 基本上,后者告诉您,abs将处理int、float、decimal等。让我们看看它是如何工作的: declare @foo2 sql_variant; set @foo2 = abs(4); select sql_variant_property(@foo2, 'BaseType') -- result: int. OK, apparently we ha

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

背景:

  • 数据类型转换:
  • 数据类型优先级:
  • Abs:
基本上,后者告诉您,
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”重载?这只是一个随机过载吗?或者是优先级列表中最高的重载(恰好是“float”)
  • 为什么不从varbinary->int应用隐式转换?毕竟,这是一个完全有效的转换
来自MSDN的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和CONVERT
图表,此转换失败。

我希望我的转换正确!欢迎评论

您已经找到了转换和优先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()

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

SELECT  CONVERT(VARBINARY(MAX), 4.00) ,CONVERT(VARBINARY(MAX), 4);
------------------   -----------------------
0x0302000190010000   0x00000004
参见
4.00
的内部表示与
4
不同?它存储精度、比例和值,而“varbinary中的int”则不是

这就是转换失败的原因
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
,并通过
ABS()
调用强制转换为
numeric
。快乐的日子。

@foo+2.0(varbinary+float)=根据您执行的隐式转换进行浮点运算。是的,但是@foo不包含浮点运算。@LesH不,不是这样的。实际上2.0是一个小数。您可以使用中间(隐式转换为)
sql\u variant
:“SELECT sql\u variant\u property((@foo+2.0),“BaseType”)-->numeric来检查这一点。至于abs,您还可以检查
abs
接受的不仅仅是一个数字——它还接受float、int等,而不进行隐式转换@当然可以。但是转换失败的原因是因为varbinary没有存储浮点数的表示形式,关键是您执行了隐式转换。我相信问题是为什么abs(varbinary)会抛出一个错误。这是一个很好的调用,但显然它不是那样工作的。第一个表达式返回
int
,第二个表达式返回
float
——如果你说的是真的,那么这两个表达式都应该返回
numeric
@atlaste So
set@foo=cast(4为varbinary(4))是int吗?因为运行
selectsql\u variant\u属性(@foo,'BaseType')
会返回varbinary。我对你的评论有点困惑。等等,我误解了你。是的,它似乎选择了最不可能的重载候选项(例如,顶部的数值表达式,而不是最接近原始类型的表达式)。。。这就是我所说的“或者可能是优先级列表中最高的重载(恰好是‘float’)?”然而,这只是一个猜测——我不知道这在多个参数等情况下会如何表现。@atlaste我已经用我的想法更新了我的答案。希望是赖特帮助我们的朋友。