【问题标题】:How to restrict NULL as parameter to stored procedure SQL Server?如何将 NULL 限制为存储过程 SQL Server 的参数?
【发布时间】:2010-09-24 17:22:33
【问题描述】:

是否可以创建存储过程为

CREATE PROCEDURE Dummy 
    @ID INT NOT NULL
AS
BEGIN
END

为什么不能做这样的事情?

【问题讨论】:

    标签: sql sql-server stored-procedures


    【解决方案1】:

    您可以在 sproc 和 RAISERROR 中检查其是否为 NULL,以将状态报告回调用位置。

    CREATE   proc dbo.CheckForNull @i int 
    as
    begin
      if @i is null 
        raiserror('The value for @i should not be null', 15, 1) -- with log 
    
    end
    GO
    

    然后调用:

    exec dbo.CheckForNull @i = 1 
    

    exec dbo.CheckForNull @i = null 
    

    【讨论】:

    • 希望有人会更新此答案以接受错误消息的可选参数名称,接受所有常见类型(bigint、varchar、...,并且仅当它们全部为空时才引发)。
    • @crokusek 如果仍然感兴趣,我在下面发了一个新帖子。干杯。
    • 我现在没有时间更新这个,但应该注意的是,从 SQL 2014 开始,存储过程不支持 raiserror,而是被 2012 年引入的 THROW 取代
    【解决方案2】:

    您的代码是正确的、明智的,甚至是良好的实践。你只需要等待支持这种语法的SQL Server 2014

    毕竟,既然可以在编译时捕获,为什么还要在运行时捕获呢?

    另请参阅this Microsoft document 并在其中搜索Natively Compiled

    正如 dkrez 所说,可空性不被视为数据类型定义的一部分。我仍然想知道为什么不。

    【讨论】:

    • 2014 年不可用,刚刚确认。
    • @SajjanSarkar,您的评论有点短。您是否尝试过本机编译的 STP 的语法?
    【解决方案3】:

    哦,好吧,我似乎无法编辑 @Unsliced 帖子,因为“此编辑偏离了帖子的原始意图。即使是必须做出重大改变的编辑也应该努力保持帖子所有者的目标。”。

    所以(@crokusek 和所有感兴趣的人)这是我提出的解决方案:

    您可以在 sproc 和 RAISERROR 中检查其是否为 NULL,以将状态报告回调用位置。

    CREATE proc dbo.CheckForNull 
      @name sysname = 'parameter',
      @value sql_variant
    as
    begin
      if @value is null
        raiserror('The value for %s should not be null', 16, 1, @name) -- with log
    end
    GO
    

    然后调用:

    exec dbo.CheckForNull @name 'whateverParamName', @value = 1
    

    exec dbo.CheckForNull @value = null 
    

    【讨论】:

    • 我现在没有时间更新这个,但应该注意的是,从 SQL 2014 开始,存储过程不支持 raiserror,而是被 2012 年引入的 THROW 取代
    • @TheHitchenator 是的,你是对的,但我认为原始答案可以追溯到 2008 年,我现在无法对其进行测试。无论如何,改变应该是微不足道的。
    • @BigBrother 是的,我知道它早于更改,因为我发现其他人可能非常值得至少在评论中获得该信息。
    • @TheHitchenator 我完全同意
    • @TheHitchenator 你能指点我这个文件吗?我在存储过程(SQL 服务器版本 12.0)中使用 raiseerror 并没有看到任何问题。 docs.microsoft.com/en-us/sql/t-sql/language-elements/… 仅表明它确实支持 SET XACT_ABORT。
    【解决方案4】:

    您可能需要这种语法的一个原因是,当您在 C# 数据集 GUI 向导中使用 sp 时,如果没有 null 限制,它会创建带有可为 null 参数的函数。 sp body 中没有 null 检查会有所帮助。

    【讨论】:

      【解决方案5】:

      参数验证目前不是 SQL Server 中过程逻辑的一项功能,NOT NULL 只是一种可能的数据验证类型。表中的 CHAR 数据类型具有长度规范。是否也应该实施?以及如何处理异常?对于表模式中的异常处理,有一种广泛的、高度开发的和基于标准的方法;但不适用于程序逻辑,可能是因为程序逻辑是在关系系统之外定义的。另一方面,存储过程已经具有引发错误事件的现有机制,并与众多 API 和语言相关联。对参数的声明性数据类型约束没有这种支持。添加它的含义是广泛的;特别是因为它得到很好的支持和可扩展,只需添加代码:

      IF ISNULL(@param) THEN
          raise error ....
      END IF
      

      与表或 SQL 表达式的上下文相比,存储过程上下文中的 NULL 概念甚至都没有明确定义。这不是微软的定义。 SQL 标准组花费了很多年的时间来编写大量文献来确定 NULL 的行为以及该行为的定义范围。存储过程不是其中之一。

      存储过程被设计为尽可能轻量级,以使数据库性能尽可能高效。参数的数据类型不是为了验证,而是为了使编译器能够为查询优化器提供更好的信息,以编译最佳的查询计划。参数上的 NOT NULL 约束通过使编译器更复杂以实现验证参数的新目的而走向另一条路径。因此效率较低且较重。

      存储过程不写成 C# 函数是有原因的。

      【讨论】:

      • “为什么可能” - 嗯...因为它是CREATE TABLE 语句中非常常用的快捷方式,所以不是 将它用于CREATE PROCEDURE 不一致? SQL Server 以与表列完全相同的方式检查参数是否为 null 有多难?
      • 'NOT NULL' 数据类型的一部分。将其视为“可空”与“不可空”。一种是包含所有“标准”值的类型,还包含一个特殊的 NULL case 值。另一个仅包含“标准”值。这两种类型基于相同的基础值,但一种提供了一种特殊情况。
      • NOT NULL 不是数据类型的一部分。它是表的列定义的一部分。 NULL 是无类型的。你没有像 NULL INTEGER 或 NULL VARCHAR 这样的概念。是的,它是 DDL 的一部分,用于断言表中的列。 DEFAULT 也是如此,索引和外键定义也是如此。我们是说存储过程参数被认为与表列正交吗?
      猜你喜欢
      • 2010-09-12
      • 2016-09-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-06-08
      • 1970-01-01
      相关资源
      最近更新 更多