【问题标题】:Raise a Particular Error in t-SQL with RAISERROR使用 RAISERROR 在 t-SQL 中引发特定错误
【发布时间】:2025-12-30 00:25:07
【问题描述】:

我有一个具有INSTEAD OF INSERT 触发器的视图(在 SQL Server 2005 中)。当用户插入视图时,他们实际上是在对许多表进行插入和更新。该视图非常复杂,以至于它不能有索引,因此不幸的是不受约束。

从 C# 中插入视图时使用的代码可能难以更改。此代码使用以下内容捕获主键和唯一键违规:

try
{
    ... // Insert into view
}
catch (SqlException ex)
{
    if (ex.Number == 2627 || ex.Number == 2601) // Primary key exception, unique constraint violation
    {
        ... // Report the duplicate entry to the user
    }
    else
    {
        throw;
    }
}

所以我的问题是:我可以在触发器中使用RAISERROR 来创建编号为 2627 或 2601 的异常吗?

【问题讨论】:

    标签: sql-server-2005 tsql raiserror


    【解决方案1】:

    没有。您将不得不等待THROW in the next release(也许)

    你只能抛出你已经放入 sys.messages (50000+) 的错误,或者给出 50000 的文本。或者将它嵌入到文本中并更改你的 c#。你不能抛出小于 50000 的错误

    如果视图太复杂以至于不能使用 DRI,那么它复杂了。此外,您还会遇到并发问题:重叠调用在您自己滚动时会在某些时候破坏您的“唯一性”。

    【讨论】:

    • 谢谢,很公平。我的理解是,只有在没有左连接、联合和子查询的情况下,架构绑定视图才能在 SQL Server 2005 中被索引。在我看来,这些并不一定会使视图过于复杂。
    • @Paul:他们这样做是因为维护索引视图需要对这些结构进行大量处理。请参阅“为什么我不能在索引视图中使用 OUTER JOIN?”在msdn.microsoft.com/en-us/library/dd171921%28SQL.100%29.aspx
    • 对不起,我的意思是太复杂而不能用作视图,对于 SQL Server 维护索引来说也不是太复杂。在我的例子中,视图没有外连接,但有一个子查询,以便我可以根据 ROW_NUMBER() 函数的结果进行限制。
    • @Paul: ROW_NUMBER() 需要重新计算整个索引视图(在 ORDER BY 中更改位置/删除,更改分区等)。索引视图的限制是有充分理由的。
    【解决方案2】:

    我不确定您是否真的可以RAISE 真正违反主键。尽管您可以使用自己的消息RAISE您自己的错误,然后catch。这还可以让您区分真正的主键违规和您自己的自定义违规。

    也许最粗略的方法是……

    SQL 代码(可能在TRIGGER 定义中)...

    RAISERROR('Custom View Violation',16,1);
    

    C#...

    try 
    {
        //execute SP / Insert etc...
    }
    catch (SqlException ex)
    {
        if (ex.Message.Split('\r')[0] == "Custom View Violation")
        {
            //deal with your exception
        }
    }
    

    【讨论】:

    • 谢谢...如果无法引发主键错误,这很可能是我需要做的。或者,我可以通过将两个相同的值插入带有主键的临时表中来导致真正的主键违规......虽然两者看起来都有点 hacky :-S
    • @Paul 是的,他们有点老套——尽管我想说我帖子中的方法比你建议的双 INSERT 少老套。我也确信RAISE 有更好的方法来处理错误并捕获您的特定异常,因此最好阅读RAISERROR 的来龙去脉。
    • 是的,同意。 [还有更多字符]