【问题标题】:Sub queries in check constraint检查约束中的子查询
【发布时间】:2017-02-08 03:52:16
【问题描述】:

我在SQL-Server 2008 R2 中设计了表格。

我在该表中有一个列,在插入数据时需要对照另一个表进行检查。

ALTER TABLE Table1
        WITH CHECK ADD CONSTRAINT CK_Code
        CHECK (MyField in (Select Field From Table2))

这会导致错误

在这种情况下不允许子查询。只允许使用标量表达式。

我看过这个关于Check Constraint - Subqueries are not allowed in this context的问题。

有什么方法可以在不使用触发器的情况下实现这一点?

【问题讨论】:

  • 外键约束不会有帮助吗?
  • Firebird 是我见过的唯一提供这种明显必要功能的产品。
  • 检查herehere。需要解决的非常糟糕的错误!

标签: sql sql-server-2008 check-constraints


【解决方案1】:

注意,您真正想要的是外键约束。也就是说,要将“查询”放入检查中,您可以编写一个包含查询并输出标量值的函数,然后在检查约束中使用该函数。

CREATE FUNCTION myFunction (
    @field DATATYPE(?)
)
RETURNS VARCHAR(5)
AS
BEGIN
    IF EXISTS (SELECT* FROM Table2 WHERE MYFIELD = @field)
        return 'True'
    return 'False'
END

类似的东西。未测试。

然后您可以像这样将其添加到您的支票中

ALTER TABLE Table1
    WITH CHECK ADD CONSTRAINT CK_Code
    CHECK (myFunction(MYFIELD) = 'True')

【讨论】:

  • @Highland 类似的东西?请注意,您可能需要在使用 myFunction 时将模式前缀添加到它。
  • 这种方法对我有用,在函数名称之前使用模式前缀(如您的评论中所述)。
  • 在我的例子中,我有 2 个表,它们通过 PK/FK 关系连接,每个表都有一个指向第三个表的外键。我想确保两个外键匹配。 FK 在两个表中以简化使用的查询。这种技术在添加“dbo”后效果很好。
  • 检查副作用的调用函数不是解决任务的正确方法。为了使检查原子函数应该在检查行(或表)时获得锁。
  • 你想要的是一个外键约束,但如果被引用的表上没有唯一键,你就不能有一个。这就是我的情况,这个解决方案很好地解决了这个问题,谢谢。
【解决方案2】:

检查约束内不能有子查询。您可以做的是使用在检查约束内返回标量值的 UDF。

第 1 步:创建表

USE CTBX
GO

CREATE TABLE RawMaterialByGender 
(
RMGID int primary key identity(1,1),
RMID smallint foreign key references RawMaterialMaster(RMID),
LeveLMasterID smallint foreign key references LevelMaster(LevelTextID),
IsDeleted bit
)

第 2 步:创建返回标量的 UDF

Create FUNCTION [dbo].[IsValidLevelMasterGender](@LevelMasterID smallint)

    RETURNS bit
    AS
    BEGIN
     DECLARE @count smallint;
     DECLARE @return bit;

     SELECT @count = count(LevelTextID)      
     FROM [LevelMaster]
     WHERE LevelCategoryID = 3 AND IsActive = 1 AND LevelTextID=@LevelMasterID

     IF(@count = 0)
     SET @return = 'false';
     ELSE
     SET @return = 'true';

     RETURN @return;

    END;
    GO

第 3 步:更改表以添加 CHECK 约束

ALTER TABLE RawMaterialByGender 
ADD CONSTRAINT check_LevelMasterID CHECK (dbo.IsValidLevelMasterGender(LeveLMasterID) = 'true')

【讨论】:

【解决方案3】:
ALTER TABLE Table1
ADD CONSTRAINT FK_Table1_Code FOREIGN KEY (MyField)
REFERENCES Table2 (Field) ;

参考:http://msdn.microsoft.com/en-us/library/ms190273.aspx
注意:我没有检查上面的语法。

【讨论】:

  • 是的,我尝试使用这种方式,但它给了我一个错误 引用表“CodeTable”中没有与外键“fk_Code”中的引用列列表匹配的主键或候选键
  • @Highland: 那么在CodeTable中定义一个主键
  • @Highland:那么问题真的是:到底为什么你的CodeTable没有主键!?!?! ? 如果它没有主键,它就不是真正的表......
  • @marc_s:是的,我确实在表中定义了一个主键。
  • @Highland:但您发布的错误消息(在您对该答案的第一条评论中)似乎与此相矛盾......主键(或唯一键)需要在您的列上'正在尝试创建对...的引用
【解决方案4】:

首先,在您的示例中,您显然需要 FK 约束。

另一种可能性是使用带有WITH CHECK OPTION 的视图并通过它授予用户访问权限:

CREATE TABLE Table1(i INT PRIMARY KEY, CK_Code CHAR(1));
CREATE TABLE Table2(Field CHAR(1));
INSERT INTO Table2(Field) VALUES ('A'),('B'), ('C');
GO

CREATE VIEW v_Table1
AS
SELECT *
FROM Table1
WHERE CK_code IN (SELECT Field FROM Table2)  -- here goes your subquery check
WITH CHECK OPTION;

当您尝试插入违反“约束”的数据时:

INSERT INTO v_Table1(i, CK_Code)
VALUES(10, 'D');

你会得到:

尝试插入或更新失败,因为目标视图指定了 WITH CHECK OPTION 或跨越了指定 WITH CHECK 的视图 OPTION 和操作产生的一或多行没有 符合 CHECK OPTION 约束条件。

语句已终止。

LiveDemo

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-12-29
    • 2023-03-16
    • 1970-01-01
    • 2011-01-28
    • 1970-01-01
    • 1970-01-01
    • 2010-11-27
    相关资源
    最近更新 更多