FOR UPDATE нельзя указывать для курсора READ ONLY - PullRequest
2 голосов
/ 13 декабря 2011

Я использую курсор для обновления одного поля в таблице, и я пытаюсь объявить курсор, используя ORDER BY в тексте выбора.

У меня есть следующие примеры данных:

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() - я знаю, что общий способ сделать это с помощью циклов, но я ни в коем случае не администратор баз данных, и в настоящее время это работает, если я удаляю my ORDER BY RecordID в объявлении курсора.

Несмотря на то, что моя текущая таблица тестов настолько мала, кажется, что она работает нормально, но причина, по которой я пытаюсь это упорядочить, заключается в том, что я вполне уверен, что она сломается, если RecordIDs не в порядке ( RecordID ASC, DupeParentID DESC) и я намерен использовать это на гораздо большем наборе записей полурегулярно. Есть ли способ определить порядок обновления курсора? Курсор как-то упорядочен автоматически? Если нет, есть ли более простой (или более быстрый) способ написать это для SQL Server 2000?

Ответы [ 2 ]

2 голосов
/ 15 декабря 2011
select recordid, max(recordguid)
from testable
where DupeParentID = 'N'
group by recordID

Приведенный выше оператор должен возвращать 1 строку для каждого идентификатора записи с максимальным значением (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)

Получите логику здесь? Что мы делаем, так это берём первый дубликат идентификатора, используя max recordguid в качестве идентификатора для «first» ... lil произвольно, мы можем использовать как min, так и до тех пор, пока он возвращает только один guID для каждого recordID. Если у вас была какая-то другая логика относительно того, какая запись должна была называться -1 по сравнению с -2, вы можете включить ее здесь.

Это создаст все recordID-1 (A-1, B-1) и оставит остальные в покое. Теперь вы должны иметь возможность зацикливать это и увеличивать -1 по мере необходимости ... или вы можете просто повторить запуск вручную, увеличивая -1 самостоятельно, если это одноразовое исправление ... ваш вызов там.

Дайте мне знать, как это происходит ... логика должна работать и будет гораздо быстрее, чем проходить все записи в каждый момент времени.

1 голос
/ 15 декабря 2011

Вы можете попробовать следующее.Хотя я не ожидаю, что производительность будет слишком высокой, я бы не рекомендовал это решение, если вам нужно регулярно выполнять запрос на работе.

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         
...