我正在写一些逻辑,允许有人声称会议时段。在创建会议(另一个表)时,所有插槽都在表中预先初始化。我需要编写一个过程来自动获取下一个可用的槽,但是确保记录保持并发并同时执行该语句不会覆盖另一个。
这是我到目前为止所拥有的,但它并不是最好的方法。
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
答案 0 :(得分:1)
您需要调查:
(UPDLOCK,READPAST,ROWLOCK)
也许是这样的:
;
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 未经测试。
但这是我要做的事情的要点:
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
编辑:
我忘了我在当天写了一个完整的'UPDATE TOP'示例:
http://granadacoder.wordpress.com/2009/07/06/update-top-n-order-by-example/
这是代码;
———-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