我们正在构建我们围绕数据库架构设计的应用程序,我们使用 IDENTITY
列作为主键。我们决定客户需要一个更“用户友好”的标识符 - YYYYDDDNNNN
形式的日期字符串,其中 YYYY
是年份,DDD
一年中的第几天,NNNN
一天中的序列,从 1 开始。
我们决定保留当前的 IDENTITY
作为父表的主键,并保留与子表的外键关系,而不是重新处理每个子表以使用这个新的复杂键,我们只是向父表添加了一个新的标识符列。问题是 - 我们希望在插入新行时自动填充此字段。
一个适度的并发症 - 我们有多个客户,他们会有重叠的序列。在 1 月 1 日,每个人都会有一个标识符为 20140010001
的记录。
因此,我们创建了一个包含 CustomerId
、LastUpdateDate
、LastSequenceNumber
的序列表。
还有一个存储过程,它传递一个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/