Member 12127164 Ответов: 1

Sql server - избегайте курсора во время последовательного обновления


Как я могу избежать использования курсора для реализации следующего? Я читал, что это можно сделать с помощью CTE, но я не получил его работы с тем же результатом.

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

Ниже вы можете увидеть код, который приносит правильные результаты:

create table #holders(Person VARCHAR(50), Kind VARCHAR(50), Pctg FLOAT)
create table #transfers(Person_FROM VARCHAR(50), Person_To VARCHAR(50), Kind VARCHAR(50), Pctg_New FLOAT, Eff_Date DATE)

insert into #holders
select 'Person One', 'Kind 1', 50 union all
select 'Person Two', 'Kind 1', 50 union all
select 'Person Three', 'Kind 1', NULL union all
select 'Person Four', 'Kind 1', NULL union all
select 'Person One', 'Kind 2', 100

insert into #transfers
select 'Person One', 'Person A', 'Kind 1', 70, '2019-12-31' union all
select 'Person Two', 'Person B', 'Kind 1', 30, '2020-01-01' union all
select 'Person A', 'Person A1', 'Kind 1', 70, '2020-01-02' union all
select 'Person A', 'Person A2', 'Kind 1', 70, '2020-01-03' union all --Should Avoided
select 'Person A2', 'Person A3', 'Kind 1', 70, '2020-01-04' union all --Should Avoided
select 'Person A1', 'Person A4', 'Kind 1', 70, '2020-01-05' 

declare
    @Person_FROM        varchar(50),
    @Person_To          varchar(50),
    @Kind               varchar(50),
    @Pctg_New           float

declare cur cursor for select Person_FROM, Person_To, Kind, Pctg_New from #transfers order by Eff_Date
open cur
fetch next from cur into @Person_FROM, @Person_To, @Kind, @Pctg_New
while @@FETCH_STATUS = 0 begin
    update #holders set Person = @Person_To, Pctg = @Pctg_New where Person = @Person_FROM AND Kind = @Kind
    fetch next from cur into @Person_FROM, @Person_To, @Kind, @Pctg_New
end
close cur
deallocate cur

SELECT * FROM #holders

drop table #holders
drop table #transfers



Результаты должны быть именно такими:
https://i.stack.imgur.com/D552U.png


Я думаю, что ключ заключается в том, что необходимо сериализованное обновление (порядок по Eff_Date) и какое-то рекурсивное (первая строка должна обновляться 3 раза, используя этот поток: "человек один" --"человек а" --"человек А1" --"человек А4").

Любая помощь приветствуется! Заранее спасибо

Что я уже пробовал:

Я попытался решить эту проблему с помощью CTE и cross join, но безуспешно

ZurdoDev

Если вам все еще нужен цикл, но вы не хотите использовать курсор, вы всегда можете использовать цикл while.

1 Ответов

Рейтинг:
0

MadMyche

Вы можете использовать цикл WHILE, чтобы повторить это с помощью обновления запроса JOIN.

Это функциональная версия этого; вы можете быть в состоянии настроить немного больше производительности из него, но он дает те же результаты, что и ваш курсор на основе разнообразия

DECLARE @DateWork DATE = (SELECT Min(Eff_Date) FROM #transfers)
DECLARE @DateStop DATE  = (SELECT Max(Eff_Date) FROM #transfers)
WHILE (@DateWork <= @DateStop) BEGIN
	UPDATE h
	SET h.Person = t.Person_To
	,   h.Pctg   = t.Pctg_New
	FROM #holders         h
	INNER JOIN #transfers t ON h.Person = t.Person_FROM AND h.Kind = t.Kind
	WHERE T.Eff_Date = @DateWork

	SET @DateWork = DateAdd(Dd, 1, @DateWork)
END