lundi 13 juin 2016

How to get rid of cursors?

I have written a SQL query that uses cursors and I realized that it eats up too many resources on the server and it is also slow.

So, this is the table:

Source

I need to calculate the time difference between Status = Assigned and Status = In Progress where Assigned_group is or prev_assigned_group is like "%Hotline%" .

I also have a sequence so I select distinct the Incident id and order the rows ascending by Incident_Sequence because I have to start with the smallest sequence number.

So far so good.

I start with the first row and jump to the next one until I find that the Status is "In Progress".When status is found I calculate the difference between the first assigned row and the row where the status In progress was found.

So the big question is: Can I do this without cursors? If yes, then how ?

SET NOCOUNT ON
DECLARE @day DATE

SET @day = '20160606'

CREATE TABLE #result(
[Assigned_Group] NVARCHAR(100),
[ProgressTime] INTEGER,
[Tickets] INTEGER,
[Avarage] FLOAT
)
INSERT INTO #result(Assigned_Group,ProgressTime,Tickets,Avarage)

SELECT DISTINCT Assigned_Group,0,0,0.0

       FROM [grs_dwh].[smt].[Aht]

   WHERE (Assigned_Group like 'CI-Hotline%' OR Prev_assigned_Group like 'CI-Hotline%')
      and CONVERT(DATE,Last_Modified_Date, 104) = @day

-- raw
SELECT [Incident_Sequence]
      ,[Incident_Id]
      ,[Assigned_Group]
      ,[Prev_assigned_Group] 
      ,[Status]
      ,[Last_Modified_Date]    
      ,[Service]

         INTO #rawData

  FROM [grs_dwh].[smt].[Aht]

WHERE (Assigned_Group like 'CI-Hotline%' OR Prev_assigned_Group like 'CI-Hotline%')
  and CONVERT(DATE,Last_Modified_Date, 104) = @day

  ORDER BY Incident_Sequence asc

  --CREATE TABLE #orderList(


  --)
  SELECT DISTINCT[Incident_id] INTO #incidentList FROM #rawData

  DECLARE cur0 CURSOR FOR SELECT incident_Id FROM #incidentList
  DECLARE @currentIncident NVARCHAR(15)

  OPEN cur0 

  FETCH next from cur0 INTO @currentIncident

  WHILE @@FETCH_STATUS = 0

       BEGIN
 -- PRINT @currentIncident
       SELECT * INTO #tmpTable FROM #rawData WHERE Incident_Id = @currentIncident ORDER BY Incident_Sequence

       DECLARE cur1 CURSOR FOR SELECT * FROM #tmpTable ORDER BY Incident_Sequence ASC

       DECLARE @incident_Sequence INTEGER
    DECLARE @incident_Id NVARCHAR(50)
    DECLARE @assigned_Group NVARCHAR(100)
       DECLARE @previous_Assiggned NVARCHAR(100)
    DECLARE @status NVARCHAR(50)
    DECLARE @last_Modified_Date DATETIME
    DECLARE @service NVARCHAR(50)

       DECLARE @progressFound BIT
       DECLARE @startProgressDate DATETIME
       DECLARE @ticketProgressTime INTEGER
       DECLARE @resultGroup NVARCHAR(100)
       SET @progressFound = 0

       OPEN cur1
       FETCH next from cur1

    INTO @incident_Sequence, @incident_Id, @assigned_Group, @previous_Assiggned, @status, @last_Modified_Date, @service

       WHILE @@FETCH_STATUS = 0

             BEGIN

                    IF @progressFound = 0 AND @status <> 'In Progress'
                    BEGIN

                    FETCH next from cur1 INTO @incident_Sequence, @incident_Id, @assigned_Group, @previous_Assiggned, @status, @last_Modified_Date, @service
                    CONTINUE
                    END

                    IF @progressFound = 0
                    BEGIN
                    SET @startProgressDate = @last_Modified_Date
                    SET @resultGroup = @assigned_Group
                    SET @progressFound = 1
                    FETCH next from cur1 INTO @incident_Sequence, @incident_Id, @assigned_Group, @previous_Assiggned, @status, @last_Modified_Date, @service
                    CONTINUE
                    END
                    ELSE
                    BEGIN
                           SET @ticketProgressTime = DATEDIFF(SECOND,  @startProgressDate,  @last_Modified_Date)


                           UPDATE #result SET ProgressTime = ProgressTime + @ticketProgressTime, Tickets = Tickets+1 WHERE Assigned_Group = @resultGroup
                           SET @ticketProgressTime = 0
                           SET @progressFound = 0
                    END
             FETCH next from cur1
             INTO @incident_Sequence, @incident_Id, @assigned_Group, @previous_Assiggned, @status, @last_Modified_Date, @service
             END
             CLOSE cur1
             DEALLOCATE cur1
             --IF @incident_Id = 'INC000010047798'
             --SELECT * FROM #tmpTable ORDER BY Incident_Sequence ASC
             DROP TABLE #tmpTable
             FETCH next from cur0 INTO @currentIncident
       END
  CLOSE cur0
  DEALLOCATE cur0
  SET NUMERIC_ROUNDABORT OFF
  UPDATE #result SET Avarage = CAST(ProgressTime AS float) / CASE WHEN Tickets = 0 THEN 1 ELSE CAST(Tickets AS float) END
   SELECT * FROM #result
   ORDER BY 1 asc
   DROP TABLE #result
   DROP TABLE #rawData
   DROP TABLE #incidentList

Aucun commentaire:

Enregistrer un commentaire