不可为空的列的UNION可以为空

时间:2016-05-31 16:56:32

标签: sql sql-server sql-server-2014-express

运行MS SQL server 2014 express。突然之间,视图中的一个列变为可空,尽管它是两个不可为空的列的并集。请帮助我理解这里发生了什么:

enter image description here

和UNION:

enter image description here

我错过了什么?

使用更多信息进行编辑:当我重新保存IncomingTransactions视图时,其列现在变为空,但它不应该是!这里是数量列的定义:( CASE PIN.StatusId WHEN 6那个PIN.QuantityReceived 7,然后0 ELSE PIN.QuantityRevised END)AS Quantity。每个数量字段都是非空的,并且case语句是详尽的。查询的其余部分是StatusId字段上的简单连接,这是一个非空的FK,所以我仍然在这里丢失。

编辑2:根据以下YB的建议,我创建了一个重现此行为的最小测试用例:

Create Table ybTest1 (Q1 decimal (7,2) not null, X int not null);
GO
Create View ybTestNSB As
Select (CASE X WHEN 0 THEN Q1 ELSE CAST(0 as decimal(7,2)) END) AS Q From ybTest1
GO

ybTest1视图中的Q列为空,即使case语句是详尽的。即使我用CAST(0 as decimal(7,2))将{0}封装在ELSE分支中,如YB所示,它仍然为空。 CASE没有我认为的语义,或者这是一个错误。

1 个答案:

答案 0 :(得分:2)

几乎每个由于表达式而计算的列在SQL Server中都被视为可为空。解决方法是使用ISNULL。 computed columns section此处

中提到了这一点
  

数据库引擎自动确定可空性   根据使用的表达式计算列。结果最多   即使只有不可为空的列,表达式也被认为是可空的   存在...可以为空的表达式可以变成a   通过指定ISNULL(check_expression, constant),不可为空的,   其中常量是替换任何空结果的非空值。

但它适用于作为计算结果导出列的任何位置,包括在视图定义中。

很少或没有逻辑来分析空值是否实际可行(有时比看起来更困难,因为各种已弃用的set选项可能会导致null而不是溢出错误,因此即使1 + X在您的示例中也可能产生null)它在谨慎方面犯了错误。我认为你的case表达式无法在现实中输出null,但根据我的经验,除isnull中包含的列外,任何计算列都将被视为可为空。

因此,在您的测试用例中,您可以替换

Create View ybTestNSB As
Select (CASE X WHEN 0 THEN Q1 ELSE CAST(0 as decimal(7,2)) END) AS Q From ybTest1

Create View ybTestNSB As
Select ISNULL(CASE X WHEN 0 THEN Q1 END, 0) AS Q From ybTest1

为了避免在那里放置一个烦人的完全多余的表达。