操作数数据类型NULL对于max运算符无效。

7

这段代码运行良好:

select fk, max(case when 1 = 0 then 1 else null end) maxx
    from (values(1, null), (1, null)) x(fk, a) 
    group by fk;

输出:

fk          maxx
----------- -----------
1           NULL

使用:

警告:空值被汇总或其他SET操作消除。

但是这段代码:

select fk, max(a) maxx
    from (values(1, null), (1, null)) x(fk, a)
    group by fk;

出现错误:

Msg 8117, Level 16, State 1, Line 5 操作数数据类型 NULL 对于 max 运算符无效。

在这两种情况下,SQL Server 从 nullnull 计算 max?难道不是吗?


2
您可以通过将 null 明确地转换为数据类型来使第二个工作项正常运行。select fk, max(a) maxx from (values(1, CAST (NULL AS varchar(25)) ), (1, CAST (NULL AS varchar(25)) )) x(fk, a) group by fk; 当列的数据类型未知时,无法获取 null 的最大值。当您尝试创建一个只有 null 值的表时,它也会失败,因为数据类型再次是未知的。 - xQbert
2个回答

9
在第一种情况下,你隐式地指定了一个数据类型,即整数。这是从then推断出来的,但then永远不会到达。事实上,对于sql server而言,then不会被执行并不重要。sql server确定返回类型的方式是:"从result_expressionsoptional else_result_expression中选择具有最高优先级的类型。因此,在实际执行之前从所有可能返回在thenelse中的数据类型中选择返回类型。换句话说,在sql server“意识到”某些语句不可能到达之前,就已经选择了返回类型。
由于已知数据类型,因此可以应用max函数。
在第二种情况下,您没有指定数据类型,因此sql server不知道如何实现max函数。对于varcharmax函数与整数是不同的。

1
那很整洁。我认为它可能应该被隐式转换为int。文档提到了inserts的情况: 多行insert语句中指定的值遵循union all语法的数据类型转换属性。 - 表值构造函数(Transact-SQL)

这两个代码将 null 值转换为 int 类型:

select null as MyNullCol
into dbo.tmp
union all 
select null as MyNullCol

select fk, a
into dbo.tmp2
from (values(1, null), (1, null)) x(fk, a)

select c.name, t.name
from sys.columns c
  inner join sys.types t
    on c.user_type_id = t.user_type_id
where c.name in ('a','mynullcol')

rextester演示:http://rextester.com/VWMT9189

返回

+-----------+------+
|   name    | name |
+-----------+------+
| MyNullCol | int  |
| a         | int  |
+-----------+------+

是的,这非常奇怪。我的测试 select fk, a INTO #T from (values(1, null), (1, null)) x(fk, a) exec tempdb.sys.sp_columns #T drop table #T 也给了我 aint 类型... - Ruslan K.
好的观点,尽管我认为你的例子应该会出现错误。如果您尝试使用null作为数据类型创建表格,它也不会被隐式转换为int。但这就是SQL Server的构建方式,我想。 - HoneyBadger
可能只有在数据插入时才会发生这种转换。 - Ruslan K.
2
@HoneyBadger 那是我的观点,因为类似的情况都是这样处理的。如果每个情况都以相同的方式处理,那对我来说也没问题! - SqlZim
文档明确提到了“多行INSERT语句”,而这不是这种情况。只要您不使用这些值来创建表,就不存在转换问题。select SQL_VARIANT_PROPERTY(a, 'BaseType') from (values(null)) x(a) 返回 NULL,和 select SQL_VARIANT_PROPERTY(NULL, 'BaseType') 相同。孤立的 NULL 不会隐式转换为类型 INT,它实际上没有类型。只是在大多数情况下,它不会长时间保持这种状态。 - Jeroen Mostert

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接