Re: Replace Cursor Procedure with Update Query?

Tech-Archive recommends: Repair Windows Errors & Optimize Windows Performance

From: Roji. P. Thomas (lazydragon_at_nowhere.com)
Date: 02/19/04


Date: Thu, 19 Feb 2004 14:21:32 +0530

1.) Can I replace the below cursor based procedure with an update
> query? How?

Yes. See below script.

DECLARE @tmpResults TABLE(Case_Id VARCHAR(15), Create_Date Int, Seq int)
INSERT INTO @tmpResults
SELECT Case_Id, Create_Date,
(SELECT Count(*) FROM #tmpSAS_Assignment_History T2
 WHERE T1.Case_Id = T2.Case_Id AND T1.Create_Date >= T2.Create_Date)
FROM #tmpSAS_Assignment_History T1
WHERE T1.Sequence Is Null
ORDER BY Case_Id, Create_Date

--SELECT * FROM @tmpResults

UPDATE SAH
SET SAH.[Sequence] = tmp.[Seq]
FROM #tmpSAS_Assignment_History SAH
INNER JOIN @tmpResults tmp
ON SAH.Case_Id = TMP.Case_Id AND SAH.Create_Date = TMP.Create_Date

-- 
Roji. P. Thomas
SQL Server Programmer
"Peter Bellis" <anonymous@discussions.microsoft.com> wrote in message
news:069AD981-3CA5-49F2-8F82-70496C67B991@microsoft.com...
> Hi all,
>
> I have a few questions for the gurus.
>
> Short version:
> 1.) Can I replace the below cursor based procedure with an update
>     query? How?
> If not ...
> 2.) I am Declaring / Deallocating one cursor inside a loop. Would it
>     be better to move the Allocation/Deallocation outside of the
>     loop? What about the variable in the Declaration?
> 3.) Any obvious bloopers/improvements?
>
> Long version:
> I have a table which is updated once a day from a live database at
> midnight. This table contains a History of how problem tickets have
> been assigned. In order for a 3rd Party app (Webfocus) to report off
> it, I have been asked to create a field "Sequence" to show in which
> order the  assignments took place. Every morning, after the update,
> I run the procedure below to update the Sequence field.
>
> When I first added the Sequence field, there were 1.6 million records
> in the table, and the procedure took 55 minutes to update the lot.
> Each night, on average, 30 000 records get added, and the procedure
> takes about 1-3 minutes to update them. So everything works. My
> reason for asking if there is alternative is because I am aware that
> cursors are not the best practice ... I just can't see how to get
> round using them in this instance. So I'm on a quest for
> understanding/efficiency.
>
> The data/structures are as follows:
> 1.) Table SAS_Assignment_History (irrelevant fields excluded)
>
> CREATE TABLE [dbo].[tmpSAS_Assignment_History] (
> [Case_Id] [varchar] (15)  NULL ,
> [Create_Date] [int] NOT NULL ,
> [Sequence] [int] NULL )
>
> 2.) View viAssHist
>
> CREATE VIEW dbo.tmpviAssHist
> AS
> SELECT Case_Id, Create_Date, Sequence
> FROM   dbo.tmpSAS_Assignment_History
>
> 3.) View viAssHistID
>
> CREATE VIEW dbo.tmpviAssHistID
> AS
> SELECT Case_Id
> FROM   dbo.tmpSAS_Assignment_History
> WHERE  (Sequence IS NULL)
> GROUP BY Case_Id
>
> 4.) Sample data for SAS_Assignment (before running the UPDATE)
>
> INSERT INTO tmpSAS_Assignment_History VALUES ('HD0000000233333',
>                                                       '1066555555', 1)
> INSERT INTO tmpSAS_Assignment_History VALUES ('HD0000000233333',
>                                                       '1066655555', 2)
> INSERT INTO tmpSAS_Assignment_History VALUES ('HD0000000233333',
>                                                    '1066755555', NULL)
> INSERT INTO tmpSAS_Assignment_History VALUES ('HD0000000233334',
>                                                    '1066555555', NULL)
> INSERT INTO tmpSAS_Assignment_History VALUES ('HD0000000233335',
>                                                    '1067555555', NULL)
> INSERT INTO tmpSAS_Assignment_History VALUES ('HD0000000233335',
>                                                    '1067655555', NULL)
> INSERT INTO tmpSAS_Assignment_History VALUES ('HD0000000233336',
>                                                       '1066555555', 1)
> INSERT INTO tmpSAS_Assignment_History VALUES ('HD0000000233336',
>                                                       '1066655555', 2)
> INSERT INTO tmpSAS_Assignment_History VALUES ('HD0000000233337',
>                                                       '1066555555', 1)
> INSERT INTO tmpSAS_Assignment_History VALUES ('HD0000000233337',
>                                                       '1066655555', 2)
> INSERT INTO tmpSAS_Assignment_History VALUES ('HD0000000233337',
>                                                    '1066755555', NULL)
> INSERT INTO tmpSAS_Assignment_History VALUES ('HD0000000233337',
>                                                    '1066855555', NULL)
>
> 5.) Output (before running the Update)
> Select * from tmpSAS_Assignment_History Order by Case_Id, Create_Date
>
> HD0000000233333 1066555555 1
> HD0000000233333 1066655555 2
> HD0000000233333 1066755555 NULL
> HD0000000233334 1066555555 NULL
> HD0000000233335 1067555555 NULL
> HD0000000233335 1067655555 NULL
> HD0000000233336 1066555555 1
> HD0000000233336 1066655555 2
> HD0000000233337 1066555555 1
> HD0000000233337 1066655555 2
> HD0000000233337 1066755555 NULL
> HD0000000233337 1066855555 NULL
>
> 6.) Output (after running the Update)
> Select * from tmpSAS_Assignment_History Order by Case_Id, Create_Date
>
> HD0000000233333 1066555555 1
> HD0000000233333 1066655555 2
> HD0000000233333 1066755555 3
> HD0000000233334 1066555555 1
> HD0000000233335 1067555555 1
> HD0000000233335 1067655555 2
> HD0000000233336 1066555555 1
> HD0000000233336 1066655555 2
> HD0000000233337 1066555555 1
> HD0000000233337 1066655555 2
> HD0000000233337 1066755555 3
> HD0000000233337 1066855555 4
>
> Comments:
> 1.) Yes, I know I should have a primary key ... I'm not in control of
>     that.
> 2.) Yes, I know the Sequence field is actually redundant, but the
>     Webfocus query requires it, I've been told (for a max(Sequence)
>     ... ).
>
> Procedure follows:
>
> ********************************************************
>
> DECLARE @hd_str varchar(15), @ts_date bigint, @sq_int int, @ts_int
>                         int, @ts_str varchar(15), @hd_str1 varchar(15)
>
> DECLARE ahistID_cursor CURSOR FOR
> SELECT * FROM tmpviAssHistID Order by Case_ID
> Open ahistID_cursor
> FETCH NEXT FROM ahistID_cursor
> INTO @hd_str
>
> WHILE @@FETCH_STATUS = 0
> BEGIN
>   DECLARE ahist_cursor CURSOR FOR
>   SELECT * FROM tmpviAssHist Where Case_ID = @hd_str
>   ORDER by Create_Date
>   OPEN ahist_cursor
>
>   FETCH NEXT FROM ahist_cursor
>   INTO @hd_str1, @ts_date, @sq_int
>   SELECT @ts_int = 1
>   SELECT @ts_str = @hd_str
>
>   WHILE @@FETCH_STATUS = 0
>   BEGIN
>     IF @sq_int is Null
>     BEGIN
>       UPDATE tmpSAS_Assignment_History
>         SET Sequence = @ts_int
>   Where Case_Id = @hd_str AND Create_Date = @ts_Date
>     END
>     Select @ts_int = @ts_int + 1
>     FETCH NEXT FROM ahist_cursor
>     INTO @hd_str1, @ts_date, @sq_int
>   END
>
>   CLOSE ahist_cursor
>   DEALLOCATE ahist_cursor
>
>   FETCH NEXT FROM ahistID_cursor
>   INTO @hd_str
> END
> CLOSE ahistID_cursor
> DEALLOCATE ahistID_cursor
>
> ************************************************************
> Procedure Ends.
>
> Thanks a mil,
> Peter Bellis
> Sunny South Africa


Relevant Pages

  • Replace Cursor Procedure with Update Query?
    ... I am Declaring / Deallocating one cursor inside a loop. ... I run the procedure below to update the Sequence field. ... DECLARE ahistID_cursor CURSOR FOR ... FETCH NEXT FROM ahistID_cursor ...
    (microsoft.public.sqlserver.programming)
  • Re: Cursor loop
    ... I've created a stored procedure that loops through a cursor, ... DECLARE curPeriod CURSOR LOCAL for SELECT * FROM tblPeriods ... The problem is that this loop only executes one time, ...
    (comp.databases.ms-sqlserver)
  • Re: Optimize function that uses cursors
    ... > The function can be made recursive as there are no much recursions (we ... > groups and ancestor groups (i.e. the parents of the parents and so on) for ... > a recursive call in the select of the cursor), and in the cursor look it ... > declare @more bit ...
    (microsoft.public.sqlserver.programming)
  • Re: Help Optimize Code
    ... Next cursor is used for all user accounts (t0, t1, ... DECLARE @name VARCHAR ... DECLARE @getAccountID CURSOR ... SELECT 't0' UNION ALL SELECT 't1' UNION ALL SELECT 't2' UNION ALL ...
    (microsoft.public.sqlserver.programming)
  • Re: SQL Procedure Optimisation
    ... Any reason why you did not mention what DBMS product? ... I'm using a cursor to perform updates based on an ID. ... DECLARE @Site_ID NVARCHAR ... due to your EAV design of the source ...
    (comp.databases)