Конвертировать курсор в T- SQL - PullRequest
1 голос
/ 26 января 2020

У меня есть курсор ниже, который отлично работает. Основная проблема заключается в том, что для ее выполнения требуется более часа.

Может кто-нибудь увидеть, как его можно преобразовать в оператор T- SQL?

DECLARE @VisitID int
DECLARE @PreviousVisitID int
DECLARE @VisitTimeIn datetime
DECLARE @Area1TimeIn datetime
DECLARE @Area1TimeOut datetime
DECLARE @Area2TimeIn datetime
DECLARE @Area2TimeOut datetime
DECLARE @Area3TimeIn datetime
DECLARE @Area3TimeOut datetime

DECLARE db_cursor CURSOR FOR 
select distinct VisitID from #temp

OPEN db_cursor  
FETCH NEXT FROM db_cursor INTO @VisitID  

WHILE @@FETCH_STATUS = 0  
BEGIN  

    select @VisitTimeIn = TimeIn from Visit where VisitID = @VisitID

    select @Area1TimeIn = @VisitTimeIn
    select @Area1TimeOut = DateAdd(ss,500,@Area1TimeIn)
    select @Area2TimeIn = @Area1TimeOut
    select @Area2TimeOut = DateAdd(ss,500,@Area2TimeIn)
    select @Area3TimeIn = @Area2TimeOut
    select @Area3TimeOut = DateAdd(ss,500,@Area3TimeIn)

    Update VisitTransitions Set TimeIn = @Area1TimeIn where VisitID = @VisitID and AreaName = '1'
    Update VisitTransitions Set TimeOut = @Area1TimeOut where VisitID = @VisitID and AreaName = '1'
    Update VisitTransitions Set TimeIn = @Area2TimeIn where VisitID = @VisitID and AreaName = '2'
    Update VisitTransitions Set TimeOut = @Area2TimeOut where VisitID = @VisitID and AreaName = '2'
    Update VisitTransitions Set TimeIn = @Area3TimeIn where VisitID = @VisitID and AreaName = '3'
    Update VisitTransitions Set TimeOut = @Area3TimeOut where VisitID = @VisitID and AreaName = '3'

    Update Visit Set TimeOut = @Area3TimeOut where VisitID = @VisitID

    FETCH NEXT FROM db_cursor INTO @VisitID 
END 

CLOSE db_cursor  
DEALLOCATE db_cursor 

Ответы [ 2 ]

3 голосов
/ 26 января 2020

Моя первая мысль, когда вы говорите о производительности, - убедиться, что у вас есть индекс для VisitTransitions.VisitId (и, конечно, Visit.VisitId). Но с точки зрения переписывания без итераций, мне интересно, рассматривали ли вы что-то вроде следующих двух утверждений:

UPDATE vt
SET 
 vt.TimeIn = CASE WHEN vt.AreaName = '1' THEN v.TimeIn WHEN vt.AreaName = '2' THEN DateAdd(ss, 500, v.TimeIn) ELSE DateAdd(ss, 1000, v.TimeIn) END,
 vt.TimeOut = CASE WHEN vt.AreaName = '1' THEN DateAdd(ss, 500, v.TimeIn) WHEN vt.AreaName = '2' THEN DateAdd(ss, 1000, v.TimeIn) ELSE DateAdd(ss, 1500, v.TimeIn) END
FROM VisitTransitions vt 
 INNER JOIN Visit v
  ON v.VisitID = vt.VisitID
 INNER JOIN #temp t
  ON v.VisitID = t.VisitID;

UPDATE v
SET 
  v.TimeOut = DateAdd(ss, 1500, v.TimeIn)
FROM Visit v
  ON v.VisitID = vt.VisitID
INNER JOIN #temp t
  ON v.VisitID = t.VisitID;

Это может быть не совсем верно, если у вас есть AreaNames, кроме (1,2,3) , но в принципе я думаю, что это сработает, и вы могли бы построить его.

3 голосов
/ 26 января 2020

Это не проверено, очевидно. Вы должны предоставить нам некоторые образцы данных, чтобы сделать их идеальными. Но ниже это начало. Не похоже, что вы делаете что-то особенное со значениями времени и времени, кроме добавления 500 секунд к каждому, поэтому:

BEGIN TRAN;

UPDATE vt
SET vt.TimeIn = v.TimeIn,
vt.TimeOut = DateAdd(ss,500,v.TimeIn)
FROM dbo.VisitTransitions vt
INNER JOIN #tmp t ON t.VisitId = vt.VisitId
INNER JOIN dbo.Visit v ON v.VisitID = vt.VisitID
AND AreaName = '1';

UPDATE vt
SET vt.TimeIn = DateAdd(ss,500,v.TimeIn),
vt.TimeOut = DateAdd(ss,1000,v.TimeIn)
FROM dbo.VisitTransitions vt
INNER JOIN #tmp t ON t.VisitId = vt.VisitId
INNER JOIN dbo.Visit v ON v.VisitID = vt.VisitID
AND AreaName = '2';

UPDATE vt
SET vt.TimeIn = DateAdd(ss,1000,v.TimeIn),
vt.TimeOut = DateAdd(ss,1500,v.TimeIn)
FROM dbo.VisitTransitions vt
INNER JOIN #tmp t ON t.VisitId = vt.VisitId
INNER JOIN dbo.Visit v ON v.VisitID = vt.VisitID
AND AreaName = '3';

UPDATE v
SET v.TimeOut = DateAdd(ss,1500,v.TimeIn)
FROM Visit v
INNER JOIN #tmp t ON t.VisitId = v.VisitId;

--COMMIT TRAN;
--ROLLBACK TRAN;
...