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

标签 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
The cursor is READ ONLY.
The statement has been terminated.

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

据我所知,如果基础表没有主键或唯一索引,我的游标将是只读的。但是我的表确实有一个主键。我什至删除了主键(以及依赖它的六个外键),然后重新创建它,但我仍然收到错误。

表格本身很简单:

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 错误有什么想法吗?

最佳答案

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

关于sql - 消息 16929,游标为只读 - 为什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21683157/

相关文章:

MySQL 插入和 unicode 字符

mysql - 如何在 WHERE 子句中使用别名列 day?

sql - 错误 "Conversion failed when converting the varchar value ' ABC' 到数据类型 int。”

sql-server - 检查 NHibernate 中的约束

sql - not in 和 in with null 值之间的区别

java - liquibase 3.5.X 找不到具有相对路径的 includeAll 的任何文件

mysql - 如何对两个 SELECT 查询进行排序并将它们组合起来

sql - Oracle 中的数据透视表?

sql - 根据玩过的游戏计算玩家排名

PHP和MYSQL最大可变长度?