#sql-server #tsql #stored-procedures #parameters #constraints
Вопрос:
У меня есть хранимая процедура, которая принимает строковый параметр:
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
Но это решение является и тем, и другим
а) устарел
б) работает не так, как ожидалось:
-- 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 Server вообще поддерживает эту функцию?
Ответ №1:
Метод, который вы используете в своем первом примере, является правильным. Однако что вы могли бы сделать, так это создать таблицу с принятыми значениями внутри. Тогда вы могли бы использовать 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