Когда срабатывает ограничение CHECK, строка уже находится в таблице. Поэтому функция вызывается, и поскольку запрос возвращает строку, функция возвращает 1, а не 0. Попробуйте это. Удалите ограничение, успешно вставьте строку и выполните этот запрос:
SELECT OLIID, PID, dbo.fnObjProd([PID]) FROM dbo.ObjInstanceProd;
Должно возвращаться 1 для каждого значения PID. Попробуйте добавить ограничение сейчас. Это не удастся по той же причине.
Рассматривали ли вы использование триггера для этого? Если вы используете проверочное ограничение, это превратит любую многострочную вставку или обновление в курсор за сценой. Это может абсолютно убить производительность и параллелизм в зависимости от того, как вы касаетесь ваших таблиц. Вот простой триггер INSTEAD OF INSERT для предотвращения ввода неверных значений одной операцией, даже для многострочной вставки:
CREATE TRIGGER dbo.trObjProd
ON dbo.ObjInstanceProd
INSTEAD OF INSERT AS
BEGIN
SET NOCOUNT ON;
IF NOT EXISTS
(
SELECT 1 FROM inserted
WHERE EXISTS
(
SELECT 1
FROM dbo.ObjInstanceProd AS olip
INNER JOIN dbo.ObjInstance AS oli
ON olip.OLIID = oli.OLIID
INNER JOIN dbo.ObjLevel AS ol
ON ol.OLID = oli.OLID
WHERE
ol.Name in ('Toyota','Lexus')
AND olip.PID = inserted.PID
)
)
BEGIN
INSERT ObjInstanceProd(OLIID, PID)
SELECT OLIID, PID FROM inserted;
END
ELSE
BEGIN
RAISERROR('At least one value was not good.', 11, 1);
SELECT OLIID, PID FROM inserted;
END
END
GO
Если вы собираетесь придерживаться функции, это гораздо более эффективный подход, однако вам нужно определить способ определить, что текущая вставляемая строка исключена из проверки - я не мог определить, как сделать это, потому что нет никаких ограничений на dbo.ObjInstanceProd. OLIID, PID уникален?
ALTER FUNCTION [dbo].[fnObjProd]
(
@Pid INT
)
RETURNS BIT
WITH EXECUTE AS CALLER
AS
BEGIN
RETURN
(
SELECT CASE WHEN EXISTS
(
SELECT 1
FROM dbo.ObjInstanceProd AS olip
INNER JOIN dbo.ObjInstance AS oli
ON olip.OLIID = oli.OLIID
INNER JOIN dbo.ObjLevel AS ol
ON ol.OLID = oli.OLID
WHERE
ol.Name in ('Toyota','Lexus')
AND olip.PID = @Pid
) THEN 1 ELSE 0 END
);
END
GO