Sql 尝试在一个事务中查询并更新表
存储过程的规范是:Sql 尝试在一个事务中查询并更新表,sql,sql-server,sql-server-2008-r2,Sql,Sql Server,Sql Server 2008 R2,存储过程的规范是: 要从我的表中选择并返回Id(顺序并不重要,只有找到的前1个才重要),并且在我选择该记录后,需要将其标记为'P',以便不再选择它 以下是存储过程: ALTER PROCEDURE [dbo].[r12028dxi_SandpitConsoleProofSweep] @myId INT OUTPUT AS /* DECLARE @X INT EXECUTE [xxx].[dbo].[r12028dxi_SandpitConsoleProofSweep] @X OUTPU
要从我的表中选择并返回
Id
(顺序并不重要,只有找到的前1个才重要),并且在我选择该记录后,需要将其标记为'P'
,以便不再选择它
以下是存储过程:
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
它正在返回错误消息:
执行后的事务计数表示不匹配的事务数
开始并提交语句。上一次计数=0,当前计数=1
我刚刚添加了Update
脚本和BEGIN事务
和提交事务代码>在此之前,当它看起来如下所示时,它工作正常
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
我添加了开始事务代码>/提交事务因为我想确保数据被读取到输出变量中,并且更新发生。我是否应该省略该过程的这一部分?在“提交事务”之前有“返回”;表示“提交事务”;永远不会执行。在“提交事务”之前有“返回”;表示“提交事务”;永远不会执行。给出您想要的:
一旦我选择了那个记录,它就需要被标记为“p”,所以
它不会再次被选中
您可以在一次交易中(而不是在一次交易中)实现这一点
注意:在处理并发处理(即:两个线程试图从单个队列中选择)时,锁定行为比在单个事务中执行更重要。给出您想要的:
一旦我选择了那个记录,它就需要被标记为“p”,所以
它不会再次被选中
您可以在一次交易中(而不是在一次交易中)实现这一点
注意:在处理并发处理(即:两个线程试图从单个队列中进行选择)时,更多的是锁定行为,而不是在单个事务中进行锁定。作为完全合理的选择,您还可以使用和函数,如下所示:
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\u NUMBER()
函数为[Status]为空的所有行分配排名,这允许您仅更新特定的行
在这种情况下,使用CTE作为UPDATE语句的直接目标是绝对合法的,因为CTE只从一个表中提取行。(这类似于使用in UPDATE语句。)作为完全合理的替代方案,您还可以使用a和函数,如下所示:
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\u NUMBER()
函数为[Status]为空的所有行分配排名,这允许您仅更新特定的行
在这种情况下,使用CTE作为UPDATE语句的直接目标是绝对合法的,因为CTE只从一个表中提取行。(这与使用in UPDATE语句类似。)+1谢谢-我需要进一步阅读有关正确使用脚本事务的信息
+1谢谢-我需要进一步阅读有关正确使用脚本事务的信息
我不能100%确定您想要实现什么,但我认为仍有人可以在您选择和更新之间插入一条新记录-具体取决于您的事务隔离级别。如果需要防止使用重复性的东西read@Greg我试图实现这样一种情况:我从前1条记录中选择Id
(顺序不重要),并且一旦我选择了该记录,就需要将其标记为'P'
。我编辑了这篇文章slightly@Greg在操作开始时添加了存储过程规范。我不能100%确定您想要实现什么,但我认为仍有人可以在您选择和更新之间插入一条新记录,具体取决于您的事务隔离级别。如果需要防止使用重复性的东西read@Greg我试图实现这样一种情况:我从前1条记录中选择Id
(顺序不重要),并且一旦我选择了该记录,就需要将其标记为'P'
。我编辑了这篇文章slightly@Greg在OP+1开始时添加了存储过程的规范。感谢Andrew-因此处理器将始终首先选择(即子查询),然后更新下一步?是的,您可能还希望向查询添加锁提示,即:FROM xxx.DBO.tb_r12028dxi_sandpitConsoleProfclient x WITH(UPDLOCK,ROWLOCK)
防止两个线程更新和检索同一个IDEExcellent。还有一个愚蠢的问题,RETURN
的意义是什么?我假设当一个proc有一个输出
参数时可以使用它?RETURN
是一种显式退出存储的proc的方法,如果您可以轻松检查是否需要进一步的工作,通常会出现在顶部附近,即:如果不存在(从xxx.DBO.tb_r12028dxi_SandpitConsoleProofClient x中选择“has unprocessed records”,其中ISNULL(sub.[Status],“”)!=“P”)返回
是的,这是正确的,但我建议对计数使用EXIST检查(将减少读取以确定是否需要继续该进程)+1感谢Andrew-因此处理器将始终首先选择(即子查询),然后更新
下一步?是的,您可能还希望在查询中添加锁定提示,即:FROM xxx.DBO.tb_r12028dxi_SandpitConsoleProofClient x WITH(UPDLOCK,ROWLOCK)
防止两个线程更新和检索同一个IDEExcellent。还有一个愚蠢的问题——RETURN
的意义是什么——我认为当一个进程有一个OUTPUT
参数时可以使用它?RETURN
是一种显式退出存储进程的方法,如果您可以轻松检查,通常会在顶部附近看到是否需要进一步的工作,即:如果不存在(从xxx.DBO.tbr12中选择“有未处理的记录”