【问题标题】:Sql Server adding multiple foreign key constraints to a table within a transactionSql Server 向事务中的表添加多个外键约束
【发布时间】:2021-07-09 15:37:52
【问题描述】:

我正在编写一个 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,1) primary key,
            UoMCategory varchar(100) not null
        );
        
        CREATE TABLE UoMConversion (
            UoMConversionID int not null identity(1,1) primary key,
            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;  

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

我得到的错误是:

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

表字段 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

【问题讨论】:

  • 您说您收到错误,但是,您的问题中没有包含所述错误...如果您不告诉我们,我们无法告诉您为什么您的代码无法正常工作为什么它不起作用。
  • 停下来,不要再往前走了。该错误消息告诉您什么?你看到“以前的错误”了吗?停止假设并开始真正的调试。请注意,您的 SSMS 版本在这里无关紧要 - 这是您包含的版本信息。如果您将脚本放在 TRY 块中并直接在 SSMS 查询窗口中运行,您将看到实际错误。
  • 在 tsql 中的错误处理是“棘手的” - 阅读 Erland 的讨论 here 了解更多详细信息。
  • 另外,为什么是SELECT这个错误而不是THROW呢?
  • @larnu 我是 SQL Server 新手。所以我还在学习。错误消息或至少最后一个捕获的错误是在链接中发布的带有图片的。我尝试了您的第二个建议,这导致了我的实际错误。消息 1785,级别 16,状态 0,第 234 行在表“UoMConversion”上引入 FOREIGN KEY 约束“FK__UoMConversion__UnitOfMEasure__UoMTo”可能会导致循环或多个级联路径。指定 ON DELETE NO ACTION 或 ON UPDATE NO ACTION,或修改其他 FOREIGN KEY 约束。我移除了 CASCADE,它起作用了!谢谢!

标签: sql-server tsql transactions foreign-keys


【解决方案1】:

此处无需使用 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,1) primary key,
    UoMCategory varchar(100) not null
);
        
CREATE TABLE UoMConversion (
    UoMConversionID int not null identity(1,1) primary key,
    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, Level 16, State 1, Line 30
Could not create constraint or index. See previous errors.

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-03
    • 2017-06-17
    • 2011-12-11
    • 1970-01-01
    • 1970-01-01
    • 2020-11-06
    相关资源
    最近更新 更多