简体   繁体   English

在更新该行之前,如何确保子查询结果中的一行被锁定

[英]How can I make sure a single row from a subquery result will be locked before I update that row

I am writing some logic to allow someone to claim meeting slots. 我正在写一些逻辑,允许某人声明会议席位。 All slots are pre-initialized in a table upon creating the meeting (another table). 创建会议时,所有席位都在一个表(另一个表)中预先初始化。 I need to write a procedure to automatically take the next available slot, but being sure that the record maintains concurrency and executing the statement at the same time wouldn't overwrite the other. 我需要编写一个过程以自动占用下一个可用插槽,但是要确保记录保持并发性,并且同时执行该语句不会覆盖其他记录。

Here's what I have so far, but it doesn't feel like the best way to do it. 到目前为止,这就是我所拥有的,但这并不是最好的方法。

DECLARE @MeetingSlotID int

BEGIN TRAN
    ;with ValidTeams as 
    (
      select teamcode
      from teamassignment with (nolock)
      where TeamType = 'A'
    )
    select top 1 @MeetingSlotID = meetingslotid 
    from ValidTeams v
      inner join meetings m with (nolock) on m.teamcode = v.teamcode
      inner join meetingslots s on m.meetingid = s.meetingid
    where isavailable = 'Y' agendaclosed = 'N'
    order by m.starttime, slotposition

    update meetingslots set IsAvailable = 'N', username = 'username' where meetingslotid = @MeetingSlotID
COMMIT TRAN

You'll want to investigate: 您将要调查:

( UPDLOCK, READPAST , ROWLOCK ) (UPDLOCK,READPAST,ROWLOCK)

Maybe something like this: 也许是这样的:

 ;
WITH cte1 AS       
 (  
        Select TOP 1
            ord.OrderID
FROM   
    dbo.Orders ord WITH ( UPDLOCK, READPAST , ROWLOCK ) 
WHERE 
    ord.IsPestimisticLocked = 0
)


UPDATE ords 
SET    
    IsPestimisticLocked = 1
FROM dbo.Orders ords
    join cte1 cteAlias on ords.OrderID = cteAlias.OrderID
WHERE ord.IsPestimisticLocked = 0;

--------EDIT Untested. -------- EDIT未经测试。

But here is the gist of what I would do: 但是,这是我要做的要点:

declare @RowsMarkedAsCheckedOutCount int

    BEGIN TRAN


    ;
    WITH cte1 AS       
     (  
        select top 1 meetingslotid 
        from 
            (
                select teamcode
                from teamassignment with (nolock)
                where TeamType = 'A'
            ) derived1
          inner join meetings m with (nolock) on m.teamcode = derived1.teamcode
          inner join meetingslots s WITH ( UPDLOCK, READPAST , ROWLOCK ) on m.meetingid = s.meetingid
        where isavailable = 'Y' agendaclosed = 'N'
        order by m.starttime, slotposition  
    )

    UPDATE meetingslots 
    SET    
        isavailable = 'N'
    FROM meetingslots mslots
        join cte1 cteAlias on mslots.MeetingSlotID = cteAlias.MeetingSlotID
    WHERE mslots.isavailable = 'Y';


Select @RowsMarkedAsCheckedOutCount = @@ROWCOUNT

    COMMIT TRAN

if (@RowsMarkedAsCheckedOutCount>0)
begin
print 'You got one !'
end

EDIT: 编辑:

I forgot I wrote a complete 'UPDATE TOP' example back in the day: 我忘记了我曾经写过一个完整的“ UPDATE TOP”示例:

http://granadacoder.wordpress.com/2009/07/06/update-top-n-order-by-example/ http://granadacoder.wordpress.com/2009/07/06/update-top-n-order-by-example/

Here is the code; 这是代码;

———-START TSQL

if exists (select * from dbo.sysobjects where id = object_id(N’[dbo].[Television]‘) and OBJECTPROPERTY(id, N’IsUserTable’) = 1)
      BEGIN
            DROP TABLE [dbo].[Television]
      END
GO


CREATE TABLE [dbo].[Television] (
      TelevisionUUID [uniqueidentifier] not null default NEWSEQUENTIALID() , 
      TelevisionName varchar(64) not null , 
      TelevisionKey int not null , 
      IsCheckedOut bit default 0
)     
GO


ALTER TABLE dbo.Television ADD CONSTRAINT PK_Television_TelevisionUUID
PRIMARY KEY CLUSTERED (TelevisionUUID)
GO


ALTER TABLE dbo.Television ADD CONSTRAINT CK_Television_TelevisionName_UNIQUE 
UNIQUE (TelevisionName)
GO


set nocount on

declare @counter int
select @counter = 11000
declare @currentTVName varchar(24)
declare @TopSize int
select @TopSize = 10

while @counter > 10000  — this loop counter is ONLY here for fake data,….do not use this syntax for production code
begin

      select @currentTVName = ‘TV:     ‘+ convert(varchar(24) , @counter)

      INSERT into dbo.Television ( TelevisionName , TelevisionKey ) values ( @currentTVName , @counter)

      select @counter = @counter – 1      
end


select count(*) as TV_Total_COUNT from dbo.Television 

/*
–Does not Work!
Update TOP (10) dbo.Television
      Set IsCheckedOut = 1
FROM
      dbo.Television tv
ORDER BY tv.TelevisionKey
*/
declare @AuditTrail table ( TelevisionUUID uniqueidentifier , OldIsCheckedOut bit , NewIsCheckedOut bit )

;
WITH cte1 AS       
 (  SELECT 
      TOP (@TopSize) 

   TelevisionUUID , –<<Note, the columns here must be available to the output
   IsCheckedOut        
      FROM   
            dbo.Television tv      
    WITH ( UPDLOCK, READPAST , ROWLOCK ) –<<Optional Hints, but helps with concurrency issues   
      WHERE  
            IsCheckedOut = 0              
      ORDER BY
            tv.TelevisionKey DESC        
)
UPDATE cte1
      SET  IsCheckedOut = 1
output inserted.TelevisionUUID , deleted.IsCheckedOut , inserted.IsCheckedOut into @AuditTrail ( TelevisionUUID , OldIsCheckedOut , NewIsCheckedOut )
;
print ”
print ‘Newly Checked Out Items’
select * from dbo.Television tv where tv.IsCheckedOut <> 0

print ‘Output AuditTrail’
select * from @AuditTrail
print ‘Not checked out items’
select count(*) as TVCOUNTIsNOTCheckedOut from dbo.Television tv where tv.IsCheckedOut = 0

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何修复ORA-01427:单行子查询返回的行多? - How can I fix ORA-01427: single-row subquery returns more than one row? 我该如何重写SQL更新语句子查询以仅选择一行? - How do I need to rewrite the SQL update statement subquery to select only a single row? 如何使查询避免“单行子查询返回多行”错误 - How do I make my query avoid the “single-row subquery returns more than one row” error 如何将结果集中的单行表示为多行? - How can I represent a single row from result set as multiple rows? 当我尝试在UPDATE中使用CASE时,单行子查询在Redshift中返回多个行 - single-row subquery returns more than one row in Redshift when I try to use CASE in UPDATE 用子查询结果更新多行 - Update multiple row with result of subquery 如何将多条记录打印为单行 - How can I make multiple records to be printed as a single row 如何在查询结果上使用子查询,然后对每行的计算结果进行ORDER BY? - How can I use a subquery on my query results and then ORDER BY a calculated result for each row? 它说子查询返回超过 1 行,但我不知道为什么? - It says subquery returns more than 1 row but I'm not sure why? 如何解决ORA-01427错误(单行子查询返回多个行)? - How can i resolve an ORA-01427 error (Single-row subquery returns more than one row)?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM