Sql server SQL Server:基于其他表中的列约束列

Sql server SQL Server:基于其他表中的列约束列,sql-server,constraints,Sql Server,Constraints,我试图基于另一个表的值来约束一个表的值。对于T1,列“col”允许为“A”或“B”。对于T2,列“col”允许为“C”或“D”。但如果T1.col为“B”,则T2.col不允许为“D”。它们具有T1.PK=T2.FK的多对一关系。如果我尝试在T2.col中插入D,当它加入T1.col='B'时,它应该失败 我看到了,但我不想做任何聚合函数。我目前的尝试是这样的 CREATE FUNCTION dbo.CheckAddition() RETURNS bit AS BEGIN RETURN (

我试图基于另一个表的值来约束一个表的值。对于T1,列“col”允许为“A”或“B”。对于T2,列“col”允许为“C”或“D”。但如果T1.col为“B”,则T2.col不允许为“D”。它们具有T1.PK=T2.FK的多对一关系。如果我尝试在T2.col中插入D,当它加入T1.col='B'时,它应该失败

我看到了,但我不想做任何聚合函数。我目前的尝试是这样的

CREATE FUNCTION dbo.CheckAddition()
RETURNS bit
AS BEGIN RETURN (
    SELECT CASE 
        WHEN T2.col = 'C' THEN 1
        WHEN T2.col = 'D' AND T1.col = 'A' THEN 1
        ELSE 0 
    END AS 'Check'
    FROM T1 
    INNER JOIN T2
    ON T1.PK = T2.FK
) END

GO;
ALTER TABLE Shift ADD CONSTRAINT checkAdd CHECK (dbo.CheckAddition() = 1);
但由于它不是一个集合,我得到了这个失败

Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.

我试图使T2.col不能是'D',如果使用@HasanMahmood的建议,T1.col中匹配的PK/FK='A',

,这是有效的

CREATE FUNCTION dbo.CheckAddition()
RETURNS bit
AS BEGIN RETURN (
    SELECT TOP 1 CASE 
        WHEN T2.col = 'C' THEN 1
        WHEN T2.col = 'D' AND T1.col = 'A' THEN 1
        ELSE 0 
    END AS 'Check'
    FROM T1 
    INNER JOIN T2
    ON T1.PK = T2.FK
    ORDER BY T2.PK DESC
) END

GO;
ALTER TABLE Shift ADD CONSTRAINT checkAdd CHECK (dbo.CheckAddition() = 1); 

这将修复您得到的错误

CREATE FUNCTION dbo.CheckAddition()
RETURNS bit
AS BEGIN 
DECLARE @Res BIT

    SELECT @Res = CASE 
        WHEN T2.col = 'C' THEN 1
        WHEN T2.col = 'D' AND T1.col = 'A' THEN 1
        ELSE 0 
    END 
    FROM T1 
    INNER JOIN T2
    ON T1.PK = T2.FK
    RETURN @Res 
END

GO;
ALTER TABLE Shift ADD CONSTRAINT checkAdd CHECK (dbo.CheckAddition() = 1);
但对于性能而言,安全性更好

CREATE FUNCTION dbo.CheckAddition(@FKValue INT, @Value CHAR(1))
    RETURNS bit
    AS BEGIN 
    DECLARE @Res BIT

        SELECT @Res = CASE 
            WHEN @Value = 'D' AND T1.Col = 'B' THEN 0
            ELSE 1 
        END 
        FROM T1
        WHERE T1.FK = @FKValue
        RETURN @Res 
    END

    GO;

ALTER TABLE T2 ADD CONSTRAINT checkValue CHECK (Col IN ('C','D'));
ALTER TABLE T2 ADD CONSTRAINT checkAdd CHECK (dbo.CheckAddition(FK, Col) = 1);
检查在插入值之前运行,因此,如果您的函数检查提交的值,当您设置错误值时,它不会返回错误,但当您尝试将其更改为有效值时,它会返回错误。。。
通过这种方式,在插入之前发送要验证的值…

为什么不在函数中简单地使用MAX?这绝对是一个潜在的性能问题。但您有一个标量函数作为约束读取两个似乎与约束所在的表无关的表。您的函数是标量函数,因此,您需要确保在所有可能的情况下只返回一个值…您可以在Select@Faller您正在创建一个函数,我认为还需要一些条件,你不能检查一个函数中的所有行,它可能会出现性能问题,你能描述一下你的全部要求吗?它运行,但你使用它的方式会返回误报,请检查我的回答。这正是我想要的。
CREATE FUNCTION dbo.CheckAddition(@FKValue INT, @Value CHAR(1))
    RETURNS bit
    AS BEGIN 
    DECLARE @Res BIT

        SELECT @Res = CASE 
            WHEN @Value = 'D' AND T1.Col = 'B' THEN 0
            ELSE 1 
        END 
        FROM T1
        WHERE T1.FK = @FKValue
        RETURN @Res 
    END

    GO;

ALTER TABLE T2 ADD CONSTRAINT checkValue CHECK (Col IN ('C','D'));
ALTER TABLE T2 ADD CONSTRAINT checkAdd CHECK (dbo.CheckAddition(FK, Col) = 1);