2011-12-13 13 views
2

カーソルを使用してテーブルの1つのフィールドを更新していますが、選択のテキストにORDER BYを使用してカーソルを宣言しようとしています。READ ONLYカーソルでFOR UPDATEを指定することはできません

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を削除すると現在動作します。

私の現在のテストテーブルと同じくらい小さくても問題ありませんが、これを注文しようとしているのは、RecordIDが順序どおりでないとかなり壊れてしまうということですRecordID ASC, DupeParentID DESC)、これをもっと大規模なレコードセットで半定期的に使用する予定です。更新するカーソルの順序を定義する方法はありますか?何とか自動的にカーソルが並んでいますか?そうでない場合は、SQL Server 2000用のこれを書くための簡単な(または速い)方法がありますか?

+0

私はrecord_idで注文の不足がこれを壊すかどうかわかりません。重複が-1 -2 -3等と印されているように見えるが、少し恣意的である。これを書くためのより速い方法は、ループの欠如であり、それを基にしたものに変えますが、それは難しいかもしれません。完全な副作用として、c1カーソルの母集団は、RecordIDからFRET testTable WHERE DupeParentID = 'Y'グループをrecordIDで選択する(グループは重複を排除します。 – Twelfth

+0

@Tewlfth - 現在(注文の順序で)、指定されたエラーメッセージが表示されます。それがなければ、いくつかのテストの後に実行されますが、カーソルがデータをまったく順序付けしていないように見えるので、私のカウンタは不正な数のレコードを更新します( 'A、A-1、 C-3、A、C-1、C-2 '、...)。'DupeParentID = 'Y''に関しては、' DupeParentID =' Y''(カーソル自体のために)のRecordIDを持つすべてのレコードが必要です - 'Y'レコードだけでなく、それらのすべてがRecordIDと一致するY. –

+0

これに答えるために他の誰かが走ることを期待していました...非ユニークなデータとカーソルの組み合わせはかなり残酷です。私はこれについて別の角度を試してもよろしいですか?私が間違っている場合は私を訂正してください。しかし、現在あなたはテーブルにデータを持っています。このスクリプトはワンタイム修正(IE、あなたは進行中のプロダクトでこのロジックを使うつもりはありません)として使用されています...ケース、私はあなたにこれを処理するための別のアイデアを持っています。 'testable'の中にあるものは、3つのrecordID、Dupeparent_id、Nを区別するために、あるいは実際には3つの同一のレコードをここに番号付けしていますか? – Twelfth

答えて

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

上記の文は、そのレコードIDの最大(GUID)とレコードIDごとに1行を返すべきです。 heh、スペルチェックはGUIDを変更し続けます。今度は、これらを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) 

ここでロジックを取得しますか?私たちがやっていることは、 'first' ... lilの識別子としてmax recordguidを使って最初の重複IDを取ることです。各recordIDに対してただ一つのguIDを返す限り、minも使うことができます。 -1と-2のどちらのレコードが他のロジックであれば、ここに含めることができます。

これにより、すべてのrecordID-1(A-1、B-1)が作成され、残りはそのままの状態になります。これをループして必要に応じて-1を増やすことができるはずです。または、これが一度だけ修正された場合は-1あなた自身を-1ずつ増やして繰り返してください。

どのようになっているのか教えてください。ロジックは機能するはずですが、一度に各レコードIDを調べるよりもかなり速くなります。

+0

興味深い考え方 - これを使って私は1回のループだけを使うように書き直すことができます。これは数十万のレコードを持つテーブルに対して本番で実行されます私は今夜​​/明日後にそれを試してみて、それがどのようになっているかを教えてくれるでしょう。 –

+0

何かを助けてくれれば、何十万もの人がこれにちょっとしたものです:)あなたが望むならループの前に実行しなければならない繰り返しの最大量を表す変数を設定することができます。 (recordIDを選択し、testtableから行番号としてcount(1)を選択し、duplicateparentID = 'N'グループをrecordIDで選択します)a。これにより、クエリがループするために必要な反復量が動的に割り当てられます。 – Twelfth

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   
+0

@Tewlfth –

関連する問題