考虑以下 sproc:
create or alter procedure TestSproc
as
begin
declare @ZeroBit bit = 0, @OneBit bit = 1
-- Table.Id is a nullable integer column
select iif(Table.Id is null, @ZeroBit, @OneBit) as ColumnNotNull
end
Run Code Online (Sandbox Code Playgroud)
编译完成后,运行以下命令:
select name, system_type_name, is_nullable
from sys.dm_exec_describe_first_result_set_for_object(object_id('TestSproc'), 0)
Run Code Online (Sandbox Code Playgroud)
显示ColumnNotNull
正确键入为 a的列bit
,但它可以为 null。
可空性对我来说没有意义,因为我传递给的参数iif
是非空常量,那么为什么结果列可以为空?是否有可能让它不可为空而不用包装表达式isnull
来解决这个问题,在我看来这是 - 或者更确切地说,应该是 - 不必要的?
的文档iif
没有提到可空性,只是说明此函数“从 true_value 和 false_value 中的类型中返回具有最高优先级的数据类型”。
首先,is_nullable
从docs.Microsoft.com返回的列sys.dm_exec_describe_first_result_set_for_object
具有以下定义:
如果列允许 NULL,则包含值 1,如果列不允许 NULL,则包含值 0,如果无法确定该列允许 NULL,则包含值 1。
这意味着引擎也可能会寻找无法预测返回列的可空性的情况。(这比其他任何信息都更适合您的信息-在这种情况下,它似乎没有发生)
现在,当我们简化存储过程并消除变量时:
CREATE PROCEDURE TestProc
AS
SELECT IIF('hello' = 'hello','true','false')
GO
Run Code Online (Sandbox Code Playgroud)
我们可以看到可空性消失了。
这是因为您在过程中使用的变量(@Zerobit 和 @Onebit)根据定义是 NULLABLE。变量本身在运行时设置,但变量数据类型的基础元数据仍然可以为空。
还有一种可能是查询优化器需要考虑所有场景,它不能在运行时使用变量的值来进行全用计划。
如果我们重写查询并且不设置变量的值,我们将看到相同的结果(过程返回的列元数据仍然为 NULLABLE):
CREATE PROCEDURE TestProc
AS
DECLARE @trueoutput VARCHAR(10)
DECLARE @falseoutput VARCHAR(10)
SELECT IIF('hello' = 'hello',@trueoutput,@falseoutput)
GO
Run Code Online (Sandbox Code Playgroud)
我对上述案例的建议是(正如 Mikael Eriksson 所说)使用常量 - 除非它是一个缩减示例并且这是不可能的。那么问题将是返回的数据类型始终可以为空,而不会被 ISNULL、CASE 等包裹
归档时间: |
|
查看次数: |
90 次 |
最近记录: |