Sql Server 向事务中的表添加多个外键约束

问题描述

我正在编写一个 sql server 脚本来创建几个表,然后更改这些表以添加我认为必要的外键约束。

我试图将这个脚本包装到一个事务中,以确保要么什么都不做,要么一切都完成。我遇到的问题是,当尝试在同一个表中添加外键约束时,脚本似乎给了我一个错误

到目前为止我尝试过的:

ALTER TABLE UoMConversion
ADD CONSTRAINT FK__UoMConversion__UnitOfMEasure__UoMFrom FOREIGN KEY(UoMFrom)
    REFERENCES UnitOfMeasure(UoMID)
    ON DELETE CASCADE;
ALTER TABLE UoMConversion
ADD CONSTRAINT FK__UoMConversion__UnitOfMEasure__UoMTo FOREIGN KEY(UoMTo)
    REFERENCES UnitOfMeasure(UoMID)
    ON DELETE CASCADE;

ALTER TABLE UoMConversion
ADD CONSTRAINT FK__UoMConversion__UnitOfMEasure__UoMFrom FOREIGN KEY(UoMFrom)
    REFERENCES UnitOfMeasure(UoMID)
    ON DELETE CASCADE,CONSTRAINT FK__UoMConversion__UnitOfMEasure__UoMTo FOREIGN KEY(UoMTo)
    REFERENCES UnitOfMeasure(UoMID)
    ON DELETE CASCADE;

我希望这两种方法都能奏效。但是,脚本和 DDL 被包装到一个带有 Try and Catch 的事务中。

    BEGIN TRANSACTION CreateTables 
    BEGIN TRY
    USE ProductDB
    
        CREATE TABLE UnitOfMeasure(
            UoMID int not null identity(1,1) primary key,UoMDescription varchar(255) not null,UoMAbbreviation varchar(10) not null,UoMCategoryID int   -- FK__UnitOfMeasure__UnitOfMeasureCategory
        );
        
        
        CREATE TABLE UnitOfMeasureCategory(
            UoMCategoryID int not null identity(1,UoMCategory varchar(100) not null
        );
        
        CREATE TABLE UoMConversion (
            UoMConversionID int not null identity(1,UoMFrom int not null,-- FK__UoMConversion__UnitOfMEasure__UoMFrom
            UoMTo int not null,-- FK__UoMConversion__UnitOfMeasure__UoMTo
            Factor decimal(5),UoMCategoryID int       -- FK__UoMConversion__UnitOfMeasureCategory
        );
        ALTER TABLE UoMConversion
          ADD CONSTRAINT FK__UoMConversion__UnitOfMEasure__UoMFrom FOREIGN KEY(UoMFrom)
        REFERENCES UnitOfMeasure(UoMID)
        ON DELETE CASCADE;
        ALTER TABLE UoMConversion
           ADD CONSTRAINT FK__UoMConversion__UnitOfMEasure__UoMTo FOREIGN KEY(UoMTo)
            REFERENCES UnitOfMeasure(UoMID)
            ON DELETE CASCADE;
END TRY
 
BEGIN CATCH  
    SELECT   
        ERROR_NUMBER() AS ErrorNumber,ERROR_SEVERITY() AS ErrorSeverity,ERROR_STATE() AS ErrorState,ERROR_PROCEDURE() AS ErrorProcedure,ERROR_LINE() AS ErrorLine,ERROR_MESSAGE() AS ErrorMessage;  
  
 IF @@ERROR > 0  
    ROLLBACK TRANSACTION;  
 END CATCH;  
  
 SELECT @@TRANCOUNT AS OpenTransactions


 COMMIT TRANSACTION;  

此外,当我删除两个外键语句之一时,错误就会消失。需要注意的是,这些表不存在于数据库中。所以当运行这个脚本时,数据库中没有现有的表或关系等。

我得到的错误是:

Error message

这意味着在表上添加 PRIMARY KEY 约束时遇到此错误,其中指定为 PRIMARY KEY 的列被定义为 NULLABLE。情况并非如此,因为:

表字段 UoMFrom 和 UoMTo 都是使用 not null 属性创建的,您将在上面的脚本中看到。

是否可以在事务中创建多个外键约束而不会出现此错误

任何帮助或建议将不胜感激!提前致谢。

使用的软件:

Microsoft sql Server Management Studio                      14.0.17289.0
Microsoft Analysis Services Client Tools                    14.0.1016.283
Microsoft Data Access Components (mdac)                     10.0.19041.1
Microsoft MSXML                                             3.0 6.0 
Microsoft Internet Explorer                                 9.11.19041.0
Microsoft .NET Framework                                    4.0.30319.42000
Operating System                                            6.3.19043

解决方法

此处无需使用 TRY/CATCH。只需设置 XACT_ABORT 并在事务中运行批处理。

USE ProductDB

SET XACT_ABORT ON 
BEGIN TRANSACTION 
    
CREATE TABLE UnitOfMeasure(
    UoMID int not null identity(1,1) primary key,UoMDescription varchar(255) not null,UoMAbbreviation varchar(10) not null,UoMCategoryID int   -- FK__UnitOfMeasure__UnitOfMeasureCategory
);
        
        
CREATE TABLE UnitOfMeasureCategory(
    UoMCategoryID int not null identity(1,UoMCategory varchar(100) not null
);
        
CREATE TABLE UoMConversion (
    UoMConversionID int not null identity(1,UoMFrom int not null,-- FK__UoMConversion__UnitOfMEasure__UoMFrom
    UoMTo int not null,-- FK__UoMConversion__UnitOfMeasure__UoMTo
    Factor decimal(5),UoMCategoryID int       -- FK__UoMConversion__UnitOfMeasureCategory
);
ALTER TABLE UoMConversion
    ADD CONSTRAINT FK__UoMConversion__UnitOfMEasure__UoMFrom FOREIGN KEY(UoMFrom)
REFERENCES UnitOfMeasure(UoMID) ON DELETE CASCADE;

ALTER TABLE UoMConversion
    ADD CONSTRAINT FK__UoMConversion__UnitOfMEasure__UoMTo FOREIGN KEY(UoMTo)
    REFERENCES UnitOfMeasure(UoMID) ON DELETE CASCADE;

COMMIT TRANSACTION;  

您将看到所有返回的错误消息:

Msg 1785,Level 16,State 0,Line 30
Introducing FOREIGN KEY constraint 'FK__UoMConversion__UnitOfMEasure__UoMTo' on table 'UoMConversion' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION,or modify other FOREIGN KEY constraints.
Msg 1750,State 1,Line 30
Could not create constraint or index. See previous errors.

您通过从至少一个外键中删除 ON DELETE CASCADE 来解决。