消息16929,光标只读 - 为什么?

时间:2014-02-10 16:50:41

标签: sql sql-server database stored-procedures triggers

我们正在构建围绕数据库架构设计的应用,其中我们使用IDENTITY列作为主键。已经确定客户需要更多用户友好的"标识符 - 表单YYYYDDDNNNN的日期字符串,其中YYYY是年份,DDD是一年中的某一天,NNNN是一天内的序列,从1开始

我们决定保留当前IDENTITY作为父表的主键,并保留与子表的外键关系,而不是重新处理每个子表以使用这个新的复杂键。我们只是在父表中添加了一个新的标识符列。问题是 - 我们希望在插入新行时自动填充此字段。

一个适度的并发症 - 我们有多个客户,他们将有重叠的序列。 1月1日,每个人都会有一个标识为20140010001的记录。

因此,我们创建了一个包含CustomerIdLastUpdateDateLastSequenceNumber的序列表。

传递CustomerId并返回格式化标识符的存储过程,更新序列表以跟踪已经使用的内容(这需要更新序列表,这就是为什么它不是函数)

最后,我们在父记录上有一个AFTER INSERT触发器:

ALTER TRIGGER [dbo].[tr_incidentnumber] 
   ON  [dbo].[IMincident] 
   AFTER INSERT
AS 
BEGIN
    SET NOCOUNT ON;

    DECLARE cur CURSOR FOR 
        SELECT customerid, incidentid 
            FROM inserted
        FOR UPDATE OF incidentnumber

    DECLARE @customerid NVARCHAR(32)
    DECLARE @incidentid int
    DECLARE @incidentnumber NVARCHAR(12)

    OPEN cur

    FETCH NEXT FROM cur 
        INTO @customerid, @incidentid

    WHILE (@@FETCH_STATUS = 0)
    BEGIN

        EXECUTE sp_getIMID @customerid, @incidentnumber OUTPUT

        UPDATE IMincident
            SET incidentnumber = @incidentnumber
            WHERE CURRENT OF cur

        FETCH NEXT FROM cur
            INTO @customerid, @incidentid
    END

    CLOSE cur
    DEALLOCATE cur
END

对于需要游标的触发器来说,这看起来非常简单(我们需要一个游标,因为我们为每一行调用一个存储过程,并且它必须是一个存储过程,因为函数无法更新数据库)

但是,它不起作用。我收到一个错误:

  

Msg 16929,Level 16,State 1,Procedure tr_incidentnumber,Line 34
  光标只读。
  该语句已终止。

我不明白为什么。我可以在网上找到这个错误的最佳解释:http://support.microsoft.com/KB/158773

据我所知,如果基础表没有主键或唯一索引,我的光标将是READ ONLY。但我的表确实有一个主键。我甚至放弃了主键(以及依赖它的六个外键),然后重新创建它,我仍然得到错误。

表格本身很简单:

CREATE TABLE [dbo].[IMincident](
    [customerid] [nvarchar](32) NOT NULL,
    [incidentid] [int] IDENTITY(1,1) NOT NULL,
    [createdbyoperatorid] [nvarchar](32) NOT NULL,
    [createddt] [datetime] NOT NULL,
    [currentrevisionnumber] [int] NOT NULL,
    [incidentnumber] [nvarchar](32) NULL,
 CONSTRAINT [PK_IMincident] PRIMARY KEY CLUSTERED 
(
    [incidentid] ASC
)
) ON [PRIMARY]

那么,为什么我应该收到16929错误?

1 个答案:

答案 0 :(得分:0)

我找到一种比光标更好的方法,因为它们往往很慢。此外,您在触发器中插入和删除的表格都是虚拟的,也许您可​​以将SP调用推断为已加入插入和/或删除的选择,并立即执行所有更新。根据变更集的大小,您可以轻松创建超时/锁定问题