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

时间:2019-03-20 13:41:57

标签: sql-server constraints

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

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

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.

编辑
我的整张桌子看起来像这样

CREATE TABLE [dbo].[T1](
    [PK] [bigint] IDENTITY(1,1) NOT NULL,
    [col] [char](1) NOT NULL,
 CONSTRAINT [PK_T1] PRIMARY KEY CLUSTERED 
(
    [PK] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO

ALTER TABLE [dbo].[T1]  WITH CHECK ADD  CONSTRAINT [CK_T1] CHECK  (([col]='B' OR [col]='A'))
GO

ALTER TABLE [dbo].[T1] CHECK CONSTRAINT [CK_T1]
GO


CREATE TABLE [dbo].[T2](
    [PK] [bigint] IDENTITY(1,1) NOT NULL,
    [FK] [bigint] NOT NULL,
    [col] [char](1) NOT NULL,
 CONSTRAINT [PK_T2] PRIMARY KEY CLUSTERED 
(
    [PK] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO

ALTER TABLE [dbo].[T2]  WITH CHECK ADD  CONSTRAINT [FK_T2_T1] FOREIGN KEY([FK])
REFERENCES [dbo].[T1] ([PK])
GO

ALTER TABLE [dbo].[T2] CHECK CONSTRAINT [FK_T2_T1]
GO

ALTER TABLE [dbo].[T2]  WITH CHECK ADD  CONSTRAINT [CK_T2] CHECK  (([col]='D' OR [col]='C'))
GO

ALTER TABLE [dbo].[T2] CHECK CONSTRAINT [CK_T2]
GO

如果T1.col中匹配的PK / FK ='A',我正在尝试使T2.col不能为'D'

2 个答案:

答案 0 :(得分: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);

该检查在插入值之前运行,因此,如果函数检查提交的值,则在设置错误的值时不会返回错误,但是在尝试将其更改为有效值时会返回错误。 。 这样,您可以发送要验证的值,然后再插入...

答案 1 :(得分:0)

使用@HasanMahmood的建议,此方法有效。

MyModel.architect