2011-12-13 24 views
2

我使用遊標更新表中的單個字段,並試圖在select的文本中使用ORDER BY聲明遊標。FOR UPDATE不能在READ ONLY光標上指定

我有下面的示例數據:

testTable: 
RecordGuid RecordID DupeParentID 
---------- -------- ------------ 
[guid]  A  Y 
[guid]  A  N 
[guid]  A  N 
[guid]  A  N 
[guid]  B  Y 
[guid]  B  N 
[guid]  B  N 
[guid]  C  Y 
[guid]  C  N 
[guid]  C  N 

和文字:

DECLARE @allcounter INT 
SET @allcounter = 1 

SELECT RecordID, count(*) as [NumberDupes] 
INTO #RecordGroupCounts 
FROM testTable 
GROUP BY RecordID 

DECLARE @temp VARCHAR(500) 
DECLARE @current VARCHAR(500) 

DECLARE c1 CURSOR 
FOR 
    SELECT RecordID FROM testTable WHERE RecordID IN (SELECT RecordID FROM testTable WHERE DupeParentID = 'Y') 
    ORDER BY RecordID 
FOR UPDATE OF RecordID 

OPEN c1 

FETCH NEXT FROM c1 INTO @current 
FETCH NEXT FROM c1 INTO @current 

WHILE @@fetch_status = 0 
BEGIN 
    UPDATE testTable 
    SET RecordID = RecordID + '-' + cast(@allcounter AS VARCHAR) 
    WHERE CURRENT OF c1 

    IF (@allcounter + 1) = (SELECT [NumberDupes] FROM #RecordGroupCounts WHERE RecordID = @current) 
    BEGIN 
     FETCH NEXT FROM c1 INTO @current 
     SET @allcounter = 0 
    END 
    SET @allcounter = @allcounter + 1 

    FETCH NEXT FROM c1 INTO @current 
END 
CLOSE c1 
DEALLOCATE c1 

這一切所需的輸出是:

RecordGuid RecordID DupeParentID 
---------- -------- ------------ 
[guid]  A  Y 
[guid]  A-1  N 
[guid]  A-2  N 
[guid]  A-3  N 
[guid]  B  Y 
[guid]  B-1  N 
[guid]  B-2  N 
[guid]  C  Y 
[guid]  C-1  N 
[guid]  C-2  N 

我的工作與SQL Server 2000,所以我沒有ROW_NUMBER()可用 - 我知道這樣做的常見方式是循環,但我是不意味着DBA,如果我在遊標聲明中刪除了我的ORDER BY RecordID,它目前適用。

與我目前的測試表一樣小這似乎是工作正常,但我試圖命令這個原因是,我相當肯定它會打破,如果RecordIDs不是按順序(通過RecordID ASC, DupeParentID DESC),我打算半定期地用這個更大的記錄集。有沒有辦法爲更新的遊標定義順序?遊標是否自動排序?如果沒有,是否有更簡單(或更快)的方式來編寫SQL Server 2000?

+0

我不確定是否看到在record_id上缺少訂單會導致此問題。雖然它會顯示重複標記爲-1 -2 -3等的順序......有點任意。寫這個的更快的方式是缺少一個循環並將其轉化爲基於集合的東西,但這可能是具有挑戰性的。作爲一個完整的方面說明,你的C1遊標的人口可以重做SELECT RecordID FROM testTable WHERE DupeParentID ='Y'group by recordID(該組將消除重複,我懷疑這是你的目標)。 – Twelfth 2011-12-13 22:15:36

+0

@Tewlfth - 目前(按順序排列),我得到了指定的錯誤信息。如果沒有它,經過一些測試後,它會運行,但它看起來光標沒有排序數據,所以我的計數器更新記錄不正確的數字(我得到像A,A-1,A-2, C-3,A,C-1,C-2 ......)。至於`DupeParentID ='Y'`,我需要每個RecordID爲`DupeParentID ='Y'`(對於遊標本身)的記錄 - 而不僅僅是'Y'記錄,但它們都與RecordID匹配一個Y. – 2011-12-13 22:31:40

+0

希望有人會採取行動回答這個問題......非唯一數據和遊標的混合是非常殘酷的。請介意我是否嘗試了不同的角度?糾正我,如果我錯了,但你目前有一個表中的數據,這個腳本被用作一次性更正(IE,你不打算在正在進行的產品中使用這個邏輯)...如果這是這種情況下,我確實有另一個想法來處理這個問題。他們在「可測試」中的任何內容來區分3 recordID A Dupeparent_id N,還是你實際上有3個相同的記錄號碼在這裏? – Twelfth 2011-12-14 22:49:00

回答

2
select recordid, max(recordguid) 
from testable 
where DupeParentID = 'N' 
group by recordID 

上面的語句應該返回每1成的recordId一行,MAX(GUID)爲的recordId。嘿,拼寫檢查不斷改變指導。現在我們可以用1來遞增所有這些。

update testtable 
set recordID = recordID + '-1' 
where recordguid in (select recordguid from ( select recordid, max(recordguid) recordguid 
from testable 
where DupeParentID = 'N' 
group by recordID) a) 

在這裏獲取邏輯?我們正在做的是採用第一個重複ID使用最大recordguid作爲'第一'的標識符... ...任意,我們可以使用min以及只要它返回每個recordID只有一個GUID。如果您有其他邏輯來確定哪些記錄被稱爲-1與-2,則可以將其包含在此處。

這將創建所有recordID-1(A-1,B-1),並將其餘的單獨留下。現在你應該可以循環這個並根據需要增加-1,或者你可以重複運行它,手動增加-1,如果這是一次性修復......你的電話在那裏。

讓我知道它是怎麼回事......邏輯應該工作,並且會比每次通過每個recordID快得多。

1

您可以嘗試以下操作。雖然我不希望性能會很好,但如果您需要定期對生產運行查詢,我不會推薦這種解決方案。

declare @counter int ,@continue tinyint 
set @counter =1 
set @continue = 1 
while @continue = 1 
Begin 
    update testtable 
    set testtable.recordid = testtable.recordid + ' - ' + CAST (@counter as nchar(6)) 
    from 
    testtable 
    inner join 
    ( 
    select MAX(cast(t1.guid as char(36))) as maxguid from testtable t1 
    inner join testtable t2 on t1.recordid = t2.recordid 
    where 
    t2.dupeparentid = 'y' and t1.dupeparentid = 'n' 
    group by t1.recordid 
    ) t4 

    on testtable.guid = cast (t4.maxguid as uniqueidentifier) 

    if @@ROWCOUNT = 0 
    set @continue = 0 
    set @counter = @counter + 1 
end