当要更新多行时,AFTER INSERT触发器失败

时间:2010-01-14 20:10:35

标签: sql-server sql-server-2005 triggers

长时间读者,第一次来电,以及所有......

以下是业务问题:用户发出一个或多个文档请求。稍后,将文档上载到系统。如果该文档与一个或多个请求匹配,则满足文档请求。因此,例如,可能存在一个或多个对文档A的请求。上传文档A后,将完成对文档A的所有请求。

这是我的技术问题:我在桌面上有一个AFTER INSERT触发器,用于记录文档的上传。它检查DocumentRequest表并更新与上载文档匹配的每一行。如果只有一行匹配(文档A只有一个请求),那么一切都是hunky-dory。但是,如果多个匹配,则触发器中的UPDATE语句失败 - 我看到了这个错误:

  

子查询返回的值超过1。   这是不允许的   子查询跟随=,!=,<,< =,>,> =   或者子查询用作   表达

以下是相关表格的CREATE语句:

CREATE TABLE [dbo].[DocumentRequest](
    [DocumentRequestId] [int] IDENTITY(1,1) NOT NULL,
    [BatchID] [int] NULL,
    [CertificateNum] [varchar](20) NOT NULL,
    [RequestedTypCd] [varchar](5) NULL,
    [RequestedReason] [varchar](60) NULL,
    [DestinationTypCd] [varchar](5) NULL,
    [DocumentPackageTypCd] [varchar](5) NULL,
    [RequestedDtm] [datetime] NOT NULL,
    [RequestNotes] [varchar](1000) NULL,
    [RequestStatusTypCd] [varchar](5) NOT NULL,
    [InactiveFlag] [char](1) NULL,
    [CreationDtm] [datetime] NOT NULL,
    [CreationUserID] [varchar](10) NOT NULL,
    [CompletedDtm] [datetime] NULL,
    [CompletedUserID] [varchar](10) NULL,
    [ModifiedDtm] [datetime] NULL,
    [ModifiedUserID] [varchar](10) NULL,
 CONSTRAINT [XPKDocumentRequest] PRIMARY KEY NONCLUSTERED 
(
    [DocumentRequestId] ASC
)WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]

--------------
CREATE TABLE [dbo].[DocumentRequestContents](
    [DocumentTypCd] [varchar](5) NOT NULL,
    [CreationDtm] [datetime] NOT NULL,
    [CreationUserID] [varchar](10) NOT NULL,
    [DocumentRequestId] [int] NOT NULL,
    [DocumentReceivedDtm] [datetime] NULL,
    [DocumentReceivedFlag] [char](1) NULL,
    [DocumentIgnoreFlag] [char](1) NULL,
 CONSTRAINT [XPKDocumentRequestContents] PRIMARY KEY NONCLUSTERED 
(
    [DocumentRequestId] ASC,
    [DocumentTypCd] ASC
)WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]

--------------
CREATE TABLE [dbo].[DocumentStorage](
    [DocumentStorageID] [int] IDENTITY(1,1) NOT NULL,
    [CertificateNum] [varchar](10) NULL,
    [DocumentHandleID] [int] NULL,
    [DocumentTypVal] [varchar](100) NULL,
    [CreationDtm] [datetime] NULL,
    [CreationUserID] [varchar](10) NULL,
    [lastupd_user] [varchar](8) NULL,
    [lastupd_stamp] [datetime] NULL,
    [DocumentNam] [varchar](100) NULL,
PRIMARY KEY NONCLUSTERED 
(
    [DocumentStorageID] ASC
)WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]


--------------
CREATE TABLE [dbo].[DocumentProfile](
    [DocumentProfileID] [int] IDENTITY(1,1) NOT NULL,
    [DocumentTypCd] [varchar](5) NULL,
    [DocumentVersionNum] [varchar](10) NULL,
    [DocumentApproveInd] [varchar](1) NULL,
    [CreationDtm] [datetime] NULL,
    [CreationUserID] [varchar](10) NULL,
    [lastupd_stamp] [datetime] NULL,
    [lastupd_user] [varchar](8) NULL,
    [DocumentStorageTypVal] [varchar](100) NULL,
    [MIMETypVal] [varchar](50) NULL,
    [DocumentSourceTypCd] [varchar](5) NULL,
    [DocumentFormatTypCd] [varchar](5) NULL,
    [DocumentReceiveLocationTypCd] [varchar](5) NULL,
    [DocumentIndexTypCd] [varchar](5) NULL,
    [DocumentNam] [varchar](100) NULL,
    [DocumentTrackedInd] [char](1) NULL CONSTRAINT [DF_DocumentProfile_DocumentTrackedInd]  DEFAULT ('N'),
PRIMARY KEY NONCLUSTERED 
(
    [DocumentProfileID] ASC
)WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]

触发器......

CREATE TRIGGER [trg_DMTDocumentReceived_DocumentStorage]
   ON  [dbo].[DocumentStorage]
   AFTER INSERT
AS 
BEGIN
    SET NOCOUNT ON;

    UPDATE DocumentRequestContents
    SET DocumentRequestContents.DocumentReceivedFlag = 'Y',
        DocumentRequestContents.DocumentReceivedDtm = getdate()
    FROM
        DocumentRequestContents
        INNER JOIN DocumentRequest
            ON DocumentRequestContents.DocumentRequestId = DocumentRequest.DocumentRequestId
        INNER JOIN DocumentProfile
            ON DocumentRequestContents.DocumentTypCd = DocumentProfile.DocumentTypCd
        INNER JOIN Inserted
            ON DocumentProfile.DocumentStorageTypVal = Inserted.DocumentTypVal
    WHERE
        (DocumentRequestContents.DocumentReceivedFlag <> 'Y' OR
            DocumentRequestContents.DocumentReceivedFlag IS NULL)
        AND (DocumentRequest.InactiveFlag IS NULL)
        AND (DocumentRequest.CertificateNum = Inserted.CertificateNum)
        AND (DocumentProfile.DocumentStorageTypVal = Inserted.DocumentTypVal)
END

从这里开始,我有点不知所措。你能帮一个人吗?

修改 请求可以有多个文档,因此触发器中正在更新的表(DocumentRequestContents)上也有一个触发器,它确定是否已满足整个请求。据我所知,它也没有子查询,但这里是:

CREATE TRIGGER [trg_DMTDocumentReceived_CompletenessCheck]
   ON  [dbo].[DocumentRequestContents] 
   AFTER UPDATE
AS 
BEGIN
    SET NOCOUNT ON;

    DECLARE @TotalDocs int, @ReceivedDocs int

    IF UPDATE(DocumentReceivedFlag)
    BEGIN
        IF (SELECT DocumentReceivedFlag FROM Inserted) = 'Y' AND (SELECT DocumentReceivedFlag FROM Deleted) = 'N'
        BEGIN
            SELECT @TotalDocs = count(*)
            FROM DocumentRequestContents
                INNER JOIN Inserted
                    ON DocumentRequestContents.DocumentRequestID = Inserted.DocumentRequestID
            WHERE (DocumentRequestContents.DocumentIgnoreFlag <> 'Y' OR DocumentRequestContents.DocumentIgnoreFlag IS NULL)

            SELECT @ReceivedDocs = count(*)
            FROM DocumentRequestContents
                INNER JOIN Inserted
                    ON DocumentRequestContents.DocumentRequestID = Inserted.DocumentRequestID
            WHERE DocumentRequestContents.DocumentReceivedFlag = 'Y'

            IF (@ReceivedDocs = @TotalDocs)
            BEGIN
                UPDATE DocumentRequest
                SET RequestStatusTypCd = 'CMPLT',
                    CompletedDtm = getdate(),
                    CompletedUserID = 'SYSTEM',
                    ModifiedDtm = getdate(),
                    ModifiedUserID = 'SYSTEM'
                FROM DocumentRequest
                    INNER JOIN Inserted 
                        ON DocumentRequest.DocumentRequestId = Inserted.DocumentRequestId
            END
        END
    END
END

谢谢, 杰森

5 个答案:

答案 0 :(得分:3)

违规行似乎在这里:

IF (SELECT DocumentReceivedFlag FROM Inserted) = 'Y' AND
   (SELECT DocumentReceivedFlag FROM Deleted) = 'N' ...

这基本上是一个“子查询”。编写IF语句时期望inserteddeleted中只有一行。在不知道业务逻辑在这里的细节的情况下,我只能推测,但如果您只是将其重写为:

,那么很可能你会好的。
IF EXISTS(SELECT 1 FROM inserted WHERE DocumentReceivedFlag = 'Y') AND
   EXISTS(SELECT 1 FROM deleted WHERE DocumentReceivedFlag = 'N'))

但它可能比那更复杂......可能你实际上需要将插入的行连接到已删除的行并检查标志是否实际上已从'Y'更改为'N'。

答案 1 :(得分:1)

检查DocumentRequestContents是否也没有触发器。

答案 2 :(得分:1)

重新阅读时,明显的问题是第二次触发的这一部分:

IF (SELECT DocumentReceivedFlag FROM Inserted) = 'Y' 
    AND (SELECT DocumentReceivedFlag FROM Deleted) = 'N'

如果插入了多行,则会失败,因为SQL Server希望这两个子查询都返回一行或没有行。

顺便说一下,我个人不惜一切代价避免使用触发器。它们给我带来了太多的复杂性。

答案 3 :(得分:0)

您可能希望尝试对联接中的Inserted表进行别名处理。虽然我自己没有经历过这种情况,但它可能会尝试在WHERE子句中执行子查询,而不是使用连接表。

答案 4 :(得分:0)

您的触发器似乎在其中的任何位置都没有子查询 - 这是您桌面上唯一的触发器?此错误不是由连接或多行更新引起的,因此我不知道为什么您的触发器会产生此错误。

当您尝试插入表格本身时,是否收到错误?也许它实际上是你用来插入失败的查询 - 请发布那个插入语句。