我在Sybase中有一个简单的表,假设它看起来如下:
CREATE TABLE T
(
name VARCHAR(10),
entry_date datetime,
in_use CHAR(1)
)
我希望根据“entry_date”的顺序获取下一个条目,并立即将“in_use”更新为“Y”,以指示该记录不可用于下一个查询。来说,如果两次执行,那就是路径尝试在我想要第二个阻塞的同时运行查询,因此它不会获取相同的记录。
问题是我发现如果你有一个ORDER BY子句,你不能在Sybase中执行“SELECT FOR UPDATE”,因此由于以下错误而无法创建以下存储过程,因为ORDER BY子句在select - 使用READ ONLY游标时错误地指定了“'FOR UPDATE'。
有没有更好的方法来获取下一条记录,锁定它,并在一个原子步骤中更新所有记录?
CREATE PROCEDURE dbo.sp_getnextrecord
@out1 varchar(10) out,
@out2 datetime out
AS
DECLARE @outOne varchar(10), @outTwo datetime
BEGIN TRANSACTION
-- Here is the problem area Sybase does not like the
-- combination of 'ORDER BY' and 'FOR UPDATE'
DECLARE myCursor CURSOR FOR
SELECT TOP 1 name, entry_date FROM T
WHERE in_use = 'N'
ORDER BY entry_Date asc FOR UPDATE OF in_use
OPEN myCursor
FETCH NEXT FROM myCursor
INTO @outOne, @outOne
-- Check @@FETCH_STATUS to see if there are any more rows to fetch.
WHILE @@FETCH_STATUS = 0
BEGIN
UPDATE t SET IN_USE = 'Y' WHERE
name = @outOne AND entry_date = @outTwo
SELECT @out1 = @outOne
SELECT @out2 = @outTwo
-- This is executed as long as the previous fetch succeeds.
FETCH NEXT FROM myCursor
INTO @outOne, @outTwo
END
CLOSE myCursor
DEALLOCATE myCursor
COMMIT TRANSACTION
答案 0 :(得分:0)
因为你只选择一行(TOP 1),为什么不使用standard locking hint而忘记光标:
BEGIN TRANSACTION
SELECT @PK=ID FROM YourTable WITH (UPDLOCK, HOLDLOCK, READPAST) WHERE ...
UPDATE ....
WHERE pk=@PK
COMMIT
如果你真的需要循环,谷歌“CURSOR FREE LOOP”
What are the different ways to replace a cursor?
在使用SELECT上的锁定提示时,您可以通过选择下一个MIN(PK)> @CurrentPk来循环。