SQL Server:基于另一个表中的列的约束列

问题描述 投票:0回答:2

我试图根据另一个表的值约束一个表的值。对于T1,列'col'允许为'A'或'B'。对于T2列,'col'允许为'C'或'D'。但如果T1.col为'B',T2.col不允许为'D'。它们具有T1.PK = T2.FK的多对一关系。如果我尝试在加入T1.col ='B'时在T2.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

我试图让它如此T2.col不能是'D',如果匹配的PK / FK在T1.col ='A'

sql-server constraints
2个回答
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);

检查在插入值之前运行,因此,如果您的函数检查提交的值,当您设置错误值时它不会返回错误,但是当您尝试将其更改为有效值时它将...您在插入之前发送要验证的值...


0
投票

使用@ HasanMahmood的建议,这是有效的。

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); 
© www.soinside.com 2019 - 2024. All rights reserved.