存储过程的规范是:
要从我的表格Id
中选择并返回tb_r12028dxi_SandpitConsoleProofClient
(订单并不重要,只有前面的1个会发现),一旦我选择了该记录,就需要将其标记为{{1}这样它就不会再次被选中。
这是存储过程:
'P'
它返回错误消息:
EXECUTE后的事务计数表示不匹配的数量 BEGIN和COMMIT语句。先前的计数= 0,当前计数= 1.
我刚刚添加了ALTER PROCEDURE [dbo].[r12028dxi_SandpitConsoleProofSweep]
@myId INT OUTPUT
AS
/*
DECLARE @X INT
EXECUTE [xxx].[dbo].[r12028dxi_SandpitConsoleProofSweep] @X OUTPUT
SELECT @X
*/
DECLARE @NumQueue INT = (
SELECT [cnt] = COUNT(*)
FROM xxx.DBO.tb_r12028dxi_SandpitConsoleProofClient
WHERE [Status] IS NULL
);
IF @NumQueue > 0
BEGIN
BEGIN TRANSACTION;
DECLARE @foundID INT = (SELECT TOP 1 Id FROM xxx.DBO.tb_r12028dxi_SandpitConsoleProofClient WHERE [Status] IS NULL);
UPDATE x
SET x.[Status] = 'P'
FROM xxx.DBO.tb_r12028dxi_SandpitConsoleProofClient x
WHERE x.Id = @foundID
SET @myId = @foundID;
RETURN;
COMMIT TRANSACTION;
END;
GO
脚本以及Update
和BEGIN TRANSACTION;
,之后它看起来像以下情况一样正常...
COMMIT TRANSACTION;
我添加了ALTER PROCEDURE [dbo].[r12028dxi_SandpitConsoleProofSweep]
@myId INT OUTPUT
AS
/*
DECLARE @X INT
EXECUTE [xxx].[dbo].[r12028dxi_SandpitConsoleProofSweep] @X OUTPUT
SELECT @X
*/
DECLARE @NumQueue INT = (
SELECT [cnt] = COUNT(*)
FROM xxx.DBO.tb_r12028dxi_SandpitConsoleProofClient
WHERE [Status] IS NULL
);
IF @NumQueue > 0
BEGIN
SELECT TOP 1 @myId = Id FROM xxx.DBO.tb_r12028dxi_SandpitConsoleProofClient;
RETURN;
END;
GO
/ BEGIN TRANSACTION;
因为我想确保数据被读入输出变量并且UPDATE发生了。我应该省略程序的这一部分吗?
答案 0 :(得分:5)
你有“回归”;在“COMMIT TRANSACTION”之前这意味着“COMMIT TRANSACTION;”永远不会被执行。
答案 1 :(得分:2)
给你想要的:
一旦我选择了该记录,就需要将其标记为'P' 它不会再被选中。
您可以在单个陈述中实现(而不是在交易中)
ALTER PROCEDURE [dbo].[r12028dxi_SandpitConsoleProofSweep]
@myId INT OUTPUT
AS
BEGIN
UPDATE x
SET x.[Status] = 'P',
@myID = x.ID
FROM xxx.DBO.tb_r12028dxi_SandpitConsoleProofClient x
/* a sample join to get your single row in an update statement */
WHERE x.ID = (SELECT MIN(ID)
FROM xxx.DBO.tb_r12028dxi_SandpitConsoleProofClient sub
WHERE ISNULL(sub.[Status], '') != 'P')
END
注意:在处理并发处理时(即:两个线程试图从单个队列中进行选择),它更多地是关于锁定行为而不是在单个事务中执行它。
答案 2 :(得分:2)
作为完全合理的suggestion by @Andrew Bickerton的替代方案,您还可以使用CTE和ROW_NUMBER()
函数,如下所示:
WITH ranked AS (
SELECT
Id,
[Status],
rnk = ROW_NUMBER() OVER (ORDER BY Id)
FROM xxx.DBO.tb_r12028dxi_SandpitConsoleProofClient
WHERE [Status] IS NULL
)
UPDATE ranked
SET
[Status] = 'P',
@myId = Id
WHERE rnk = 1
;
ROW_NUMBER()
函数会为[Status] IS NULL
的所有行分配排名,这样您只能更新特定的行。
在这种情况下,使用CTE作为UPDATE语句的直接目标是绝对合法的,因为CTE仅从一个表中提取行。 (这类似于在UPDATE语句中使用views。)