创建要在存储过程参数值中使用的值的白名单
Create a whitelist of values to be used in a stored procedure parameter value
我有一个带字符串参数的存储过程:
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', 'val2', ...);
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', 'val2', ...)
AS
BEGIN
-- do stuff
END
但是找不到合适的语法。 SQL 服务器甚至支持此功能吗?
您在第一个示例中使用的方法是正确的。但是,您可以做的是创建一个 table 并在其中包含可接受的值。然后您可以使用 EXISTS
来检查该值对 table 是否有效。这将使您的程序更加简洁,如果您需要在多个程序中实施验证,它会使其更容易转移,并为您的验证添加价值table“更新”所有程序。
所以,简单来说:
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
我有一个带字符串参数的存储过程:
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', 'val2', ...);
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', 'val2', ...)
AS
BEGIN
-- do stuff
END
但是找不到合适的语法。 SQL 服务器甚至支持此功能吗?
您在第一个示例中使用的方法是正确的。但是,您可以做的是创建一个 table 并在其中包含可接受的值。然后您可以使用 EXISTS
来检查该值对 table 是否有效。这将使您的程序更加简洁,如果您需要在多个程序中实施验证,它会使其更容易转移,并为您的验证添加价值table“更新”所有程序。
所以,简单来说:
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