如何使视图列不为空

Posted

技术标签:

【中文标题】如何使视图列不为空【英文标题】:How to make a view column NOT NULL 【发布时间】:2011-01-20 13:45:54 【问题描述】:

我正在尝试创建一个视图,其中我希望列仅是真或假。但是,似乎无论我做什么,SQL Server (2008) 都认为我的位列可能以某种方式为空。

我有一个名为“产品”的表,其中列“状态”为INT, NULL。在一个视图中,我想为 Product 中的每一行返回一行,如果 Product.Status 列等于 3,则 BIT 列设置为 true,否则 bit 字段应为 false。

示例 SQL

SELECT CAST( CASE ISNULL(Status, 0)  
               WHEN 3 THEN 1  
               ELSE 0  
             END AS bit) AS HasStatus  
FROM dbo.Product  

如果我将此查询保存为视图并查看对象资源管理器中的列,则 HasStatus 列设置为 BIT, NULL。但它永远不应该为 NULL。我可以使用一些神奇的 SQL 技巧来强制此列为 NOT NULL

请注意,如果我删除CASE 周围的CAST(),则该列正确设置为NOT NULL,但随后该列的类型设置为INT,这不是我想要的。我希望它是BIT。 :-)

【问题讨论】:

【参考方案1】:

您可以通过稍微重新安排查询来实现您想要的。诀窍是ISNULL 必须在外部,SQL Server 才能理解结果值永远不会是NULL

SELECT ISNULL(CAST(
    CASE Status
        WHEN 3 THEN 1  
        ELSE 0  
    END AS bit), 0) AS HasStatus  
FROM dbo.Product  

我实际上发现这很有用的一个原因是使用ORM 并且您不希望将结果值映射到可为空的类型。如果您的应用程序认为该值永远不可能为空,它可以使事情变得更容易。那么你就不用写代码来处理空异常等了。

【讨论】:

@Gunder:不用担心,实际上它有点神秘。当在表中创建计算位列并希望结果不可为空时,这也很方便。 我需要类似的东西,我发现COALESCE() 不起作用,你实际上必须使用ISNULL() @EvilBob22 这很奇怪,因为 COALESCE 和 ISNULL 都可以返回 NULL。我猜只是编译器的怪癖。 这是 10 亿倍,用于让 EntityFramework 在通常不会被推断出的情况下推断出一个键。 另见:dba.stackexchange.com/questions/114260/…【参考方案2】:

仅供参考,对于遇到此消息的人来说,在强制转换/转换的外部添加 ISNULL() 可能会扰乱您视图上的优化器。

我们有 2 个表使用相同的值作为索引键,但具有不同数值精度的类型(不好,我知道),我们的观点是加入它们以产生最终结果。但是我们的中间件代码正在寻找特定的数据类型,并且视图在返回的列周围有一个 CONVERT()

我注意到,正如 OP 所做的那样,视图结果的列描述符将其定义为可为空,我在想它是 2 个表上的主键/外键;为什么我们要将结果定义为可为空的?

我找到了这篇文章,将 ISNULL() 扔到了列周围,瞧 - 不再可以为空了。

问题是当查询对该列进行过滤时,视图的性能直接下降。

由于某种原因,视图的结果列上的显式 CONVERT() 并没有搞砸优化器(由于精度不同,它无论如何都必须这样做),但是添加一个冗余的 ISNULL() 包装器确实如此,在很大程度上。

【讨论】:

您能否在示例中展示如何使用CONVERT() 确保/指示不可空性的解决方案? 嗨,O. R. - 抱歉,我有一段时间没看到这个。这是一个例子。如果您在视图中有 CONVERT(BIT,U.RETIRED),0) AS Retired,将字节或 int 列转换为位/布尔值,则它可以为空。您可以通过将其替换为 ISNULL(CONVERT(BIT,U.RETIRED),0) AS Retired 来使视图中的该列不可为空。如果开始时 U.RETIRED 不为 null,则它在功能上不会更改视图中的列之外的任何内容。警告:ISNULL() 可能会干扰查询优化和索引选择。【参考方案3】:

您在 Select 语句中所能做的就是控制数据库引擎作为客户端发送给您的数据。 select 语句对基础表的结构没有影响。要修改表结构,您需要执行 Alter Table 语句。

    首先确保表中该位字段当前没有空值 然后执行下面的ddl语句: Alter Table dbo.Product Alter column status bit not null

如果你想要做的只是控制视图的输出,那么你所做的就足够了。您的语法将保证视图结果集中 HasStatus 列的输出实际上 从不 为空。它将始终是位值 = 1 或位值 = 0。不要担心对象浏览器会说什么......

【讨论】:

我不想更改表格列。该列定义为整数列,允许为空。这符合我们的规范。但我需要一个返回带有位字段的列的视图,该字段不能为空。我知道它不能为空是不够的,该列必须为 NOT NULL,这样它才能在我们的 ORM 中正确映射。

以上是关于如何使视图列不为空的主要内容,如果未能解决你的问题,请参考以下文章

如何在 oracle 中使可空列不为空

EXCEL如何通过函数得到一列不为空值的数

SQL:如何在 B 列不为空的情况下使用“100”更新 A 列

按列分组,优先选择另一列不为空的行

如果其他列不为空,则更新 3 列

pandas 某列不为空的行