创建要在存储过程参数值中使用的值的白名单

问题描述

我有一个接受字符串参数的存储过程:

CREATE PROCEDURE sp_my_procedure
  @param1 NVARCHAR(100)
AS
BEGIN
  -- do stuff
END

但是,并非所有字符串值都是此参数的有效值。我知道我可以做到这一点:

CREATE PROCEDURE sp_my_procedure
  @param1 NVARCHAR(100)
AS
BEGIN
  IF @param1 NOT IN ('val1','val2',...)
  BEGIN
    -- raise error and then return
  END
  
  -- do stuff
END

但是这个解决方案很难阅读,这取决于我可以把支票放在哪里(需要做哪些其他检查等),并且依赖于我想避免的自定义错误号(标准化并不总是更好,但大多数情况下是这样)。

我发现的另一个解决方案是创建用户定义的数据类型并为其绑定规则:

CREATE RULE my_rule
AS
@val IN ('val1',...);
GO

CREATE TYPE RESTRICTED_STRING_TYPE
FROM NVARCHAR(100) NOT NULL;
GO

EXEC sp_bindrule 'my_rule','RESTRICTED_STRING_TYPE';
GO

但是这个解决方案是两者
a) 已弃用
b) 未按预期工作:

-- after type and rule has been created

DECLARE @val RESTRICTED_STRING_TYPE; -- this should fail because of the not null clause
SET @val = 'invalid value'; -- but even if not null is not there,this should definitely fail

PRINT(@val); -- nope,'invalid value' is printed without error

我想做这样的事情:

CREATE PROCEDURE sp_my_procedure
  @param1 NVARCHAR(100) IN ('val1',...)
AS
BEGIN
  -- do stuff
END

但是找不到正确的语法。 sql Server 甚至支持功能吗?

解决方法

您在第一个示例中使用的方法是正确的。但是,您可以做的是创建一个表,其中包含接受的值。然后您可以使用 EXISTS 来检查该值是否对表有效。这将使您的程序更加简洁,如果您需要在多个程序中执行验证,它会更容易转移,并在您的验证表中添加一个值“更新”所有程序。

所以,简单来说:

CREATE TABLE dbo.RESTRICTED_STRING_VALUES (StringValue nvarchar(100);
INSERT INTO dbo.RESTRICTED_STRING_VALUES
VALUES (N'Val1'),(N'Val2'),(N'Val3');
GO
CREATE PROCEDURE dbo.my_procedure --Don't use "sp_" as a prefix! It's reserved by Microsoft.
  @param1 NVARCHAR(100)           --Doing so comes at a performance cost,--and could result in the Proc simply not working after an update
AS
BEGIN
    IF NOT EXISTS (SELECT 1 FROM dbo.RESTRICTED_STRING_VALUES WHERE StringValue = @param1)    
    BEGIN
        --Raise error and then return
    END;
  
    --do stuff
END;
GO