2010-02-25 45 views
2

我有一個簡單的表在Sybase,讓我們說,它看起來如下:的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子句選擇 - 「‘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

因爲您只選擇了一行(TOP 1)爲什麼不只是使用standard locking hint忘記光標:

BEGIN TRANSACTION 

SELECT @PK=ID FROM YourTable WITH (UPDLOCK, HOLDLOCK, READPAST) WHERE ... 

UPDATE .... 
WHERE [email protected] 

COMMIT 

,如果你真的需要循環,谷歌 「CURSOR無環路」

What are the different ways to replace a cursor?

您可以選擇循環的下一次MIN(PK)> @ CurrentPk同時在SELECT上使用鎖定提示。

+0

嘗試:「SELECT TOP 1 @ outOne = name,@ outTwo = entry_date,in_use FROM T WITH(UPDLOCK,HOLDLOCK,READPAST)WHERE in_use ='N'」嘗試創建過程時出現錯誤:'A爲變量賦值的SELECT語句不能與數據檢索操作' – 2010-02-25 19:20:58

+0

組合使用,您可能必須使用鎖定提示將其選擇到#temp_table或@table_variable(如果sybase具有這些?),然後選擇進入變量與常規選擇。 – 2010-02-25 21:29:46

+0

鎖的提示做了竅門,謝謝 – 2010-03-03 16:54:39

相關問題