我更多地将其作为小费发布,因为我自己找到了答案(在同事的帮助下)。
我们公司的生产域(服务器P)中有一个SQL Server 2012系统,它将主数据库(M)的表(T)中的记录复制到业务域中的另一个SQL Server 2012系统(服务器B) ,相同的数据库和表名)。
我们正在业务服务器上的单独数据库(E)中安装新的ERP系统。供应商要求我将表T中的数据填充到数据库中,当它到达业务服务器时,包括来自连接表(J)和视图(V)的数据。我写了以下Trigger:
CREATE TRIGGER [dbo].[After_Insert_T] ON [dbo].[T] AFTER INSERT AS
BEGIN
SET NOCOUNT ON; -- Prevent extra result sets interfering with SELECT statements.
SET XACT_ABORT OFF; -- Avoid automatically rolling back current transaction
BEGIN TRY
INSERT E.dbo.T
SELECT inserted.C1, inserted.C2, inserted.C3, J.C5, V.C7
FROM inserted LEFT OUTER JOIN
J ON inserted.C4 = J.C1 LEFT OUTER JOIN
V ON inserted.C6 = V.C1
AND inserted.C3 BETWEEN J.C8 AND J.C9;
END TRY
BEGIN CATCH
DECLARE @ErrorMessage NVARCHAR(4000);
DECLARE @ErrorSeverity INT;
DECLARE @ErrorState INT;
SELECT @ErrorMessage = ERROR_PROCEDURE() + ': ' + ERROR_MESSAGE(),
@ErrorSeverity = ERROR_SEVERITY(),
@ErrorState = ERROR_STATE();
RAISERROR (@ErrorMessage, @ErrorSeverity, @ErrorState ,16,1) WITH LOG;
END CATCH
END
这一切都运行了好几天,但随后记录不再在Business数据库中更新,事件查看器告诉我我收到了错误:
错误:50000严重性:16状态:1 After_Insert_T:子查询返回的值超过1。当子查询遵循=,!=,<,< =,>,> =或子查询用作表达式时,不允许这样做。
我无法为我的生活弄清楚如何从我编写的SQL中获得Subquery错误。我想也许V视图有一个子查询但事实并非如此。我在网上搜索并看到一个案例,实际系统复制表中的陈旧记录导致SQL Server返回重复记录,因此我检查了所有基于复制的表,但没有发现任何错误。
然后是答案......
答案 0 :(得分:1)
ERP供应商已经在我插入的表格上编写了自己的触发器。他的SQL有一个子查询,在某些情况下会返回多行,但是他没有TRY / CATCH,所以它在我的触发器中回落到CATCH,记录了错误。我唯一感到困惑的是,我认为SET XACT_ABORT OFF
语句应该允许将原始记录写入表中,尽管有错误,所以我重读了它的帮助,看到了这个:
THROW声明表示SET XACT_ABORT RAISERROR没有。新应用程序应使用THROW而不是RAISERROR。
我的CATCH例程几乎是从RAISERROR的帮助中复制的,所以我错过了这一点。
我从中学到的教训是,仅仅因为你的代码报告问题并不理所当然地认为你造成了它!
快乐的编码。
Wayne Ivory