Click here to Skip to main content
15,899,126 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
Hi I am working in weekly Newspaper company. There are 15000 subscriber, subscribed for next 3 to 4 years.Per year 52 weeks and I have to generate issue number based on week(1001......3000) for each subscriber and store into data table. I am using mssql 2012. I have written the Store Procedure (I have given below) working fine. But it takes long time more then half an hour when execute into server. If using aspx pages, it stop working. I have also increased time out. No Use. Pls check my store procedure and advise me how to do

thank you

Maideen

My Store procesure

SQL
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

ALTER Procedure [dbo].[WR_SUB_usp_Reports_Audit] 
As
Begin 
TRUNCATE TABLE [dbo].[SUB_tbl_Reports_Audit]


    Declare @code varchar(50), @start int , @end int, @start1 int, @end1 int, @str varchar(3000),@Name varchar(150), @PKcode varchar(20)
	Declare @CurrCode varchar(5), @PaidAmt decimal, @PKAmount decimal , @PStart date, @PEnd date, @PExt date 
	Declare @DStart date,@DEnd date, @DExt date, @ACRefNo varchar(10), @NoIssue int, @AmtCharged decimal, @AmtFull decimal
	Declare @TEMPAmt decimal, @TEMDAmt decimal, @TESDAmt decimal, @ERDAmt decimal, @TEMPRate decimal, @TEMDRate decimal
	Declare @TEMPCopy decimal, @TEMDCopy Decimal, @TESDCopy int,@ERDCopy  int, @PStartIssueNo int, @PEndIssueNo int 
	Declare @DStartIssueNo int,@DEndIssueNo int

	DECLARE num_cursor CURSOR FOR 
	
	Select Code, Name,CurrCode,PaidAmt,PKAMOUNT, PStart, PEnd, PExt, DStart,   DEnd, DExt, ACRefNo, NoIssue, PStartIssueNo,PendIssueNo,DStartIssueNo,DEndIssueNo from [dbo].[SUB_tbl_Reports] 
	    
	OPEN num_cursor

    FETCH NEXT FROM num_cursor 
    INTO @code,@Name,@PKCode,@CurrCode,@PaidAmt, @PKAmount, @PStart, @PEnd, @PExt, @DStart,  @DEnd, @DExt, @ACRefNo, @NoIssue, @start,@end,@start1,@end1
    WHILE @@FETCH_STATUS = 0
    BEGIN

        While @start <= @end  or @start1 <= @end1
        Begin
            Insert into SUB_tbl_Reports_audit (code,NAME,PKCode,Currcode,PaidAmt, PKAmount, PStart, PEnd, PExt, DStart,  DEnd, DExt, ACRefNo, NoIssue, pstartissueno,DStartIssueNo) 
			Values (@code,@nAME,@PKCode,@CurrCode,@PaidAmt, @PKAmount, @PStart, @PEnd, @PExt, @DStart,  @DEnd, @DExt, @ACRefNo, @NoIssue,@start,@start1)
            Set @start= @start + 1
            Set @start1 = @start1+1
        End 

       FETCH NEXT FROM num_cursor 
       INTO @code,@name,@pkcode,@CurrCode,@PaidAmt, @PKAmount, @PStart, @PEnd, @PExt, @DStart,   @DEnd, @DExt, @ACRefNo, @NoIssue, @start,@end, @start1,@end1

    END
   
    CLOSE num_cursor
    DEALLOCATE num_cursor

End 
Posted
Comments
CHill60 12-Mar-15 8:56am    
So are you asking "how to generate a number" or "how to make my SP more performant?" - The title of your question does not match the body of the question

1 solution

It is quite possible that the CURSOR is causing database locking issues, in any event it is very slow and not a recommended approach.

An alternative to using CURSOR is to determine the number of records and use a WHILE loop (idea taken from, and further details at, SQL Cursors - how to avoid them[^])

I generated the following tables for this example
SQL
CREATE TABLE [SUB_tbl_Reports]
(
	code varchar(10),
	Pstart int,
	PEnd int
)
CREATE TABLE [SUB_tbl_Reports_Audit]
(
	code varchar(10),
	PIssueNumber int
)
insert into [SUB_tbl_Reports] values
				('A',  1, 5), 
				('B', 11, 15),
				('C', 21, 25),
				('D', 31, 35)

First step is to create a temporary table to contain the base data with an added Row Number
SQL
IF OBJECT_ID('tempdb..#Temp') IS NOT NULL BEGIN DROP TABLE #Temp END
SELECT *, ROW_NUMBER() OVER (ORDER BY code) AS ROWID INTO #temp FROM [SUB_tbl_Reports]
(You may be tempted to use an existing IDENTITY column on a table, but this will fail if any records have been deleted, leaving gaps in the ID numbers. Using Row_Number ensures that there are no gaps)

Now define and initialise the loop counter for the loop and capture the number of rows on the table
SQL
DECLARE @RowCount int
SET @RowCount = 1
DECLARE @NumRows int
SELECT @NumRows = (SELECT COUNT(*) FROM [SUB_tbl_Reports])

Now you can step through the table using the generated ROWID without locking the entire table up with a SQL WHILE loop.
SQL
DECLARE @code varchar(10)
DECLARE @PStart int
DECLARE @PEnd int
WHILE @RowCount <= @NumRows
BEGIN
    SELECT @code = code, @Pstart = Pstart, @PEnd = Pend
    from #temp where ROWID = @RowCount;

     -- ... do some stuff here

    SET @RowCount = @RowCount + 1
END

The "do some stuff here" in your case is "generate x table rows with numbers starting at value y where x and y can be derived from the original table". The easiest way to do this is to use a Common Table Expression (CTE) to generate a sequence of numbers from Pstart to Pend (extrapolated from Generating a Sequence in SQL[^])
SQL
WITH q AS
       (
       SELECT  @Pstart AS num
       UNION ALL
       SELECT num + 1
       FROM q
       WHERE num < @Pend
       )
   insert into [SUB_tbl_Reports_Audit] SELECT [#temp].code, num FROM [#temp], q WHERE ROWID = @RowCount
   OPTION (MAXRECURSION 0)
Note the MAXRECURSION hint on the select - default is 100 but the 0 removes any limitations. An alternative is to pick an appropriate number for the expected maximum number of rows you may need, but this will have to be hard-coded - a variable cannot be used.

The entire fiddle is reproduced below:
CREATE TABLE [SUB_tbl_Reports]
(
	code varchar(10),
	Pstart int,
	PEnd int
)

CREATE TABLE [SUB_tbl_Reports_Audit]
(
	code varchar(10),
	PIssueNumber int
)

insert into [SUB_tbl_Reports] values
				('A',  1, 15), 
				('B', 11, 15),
				('C', 21, 25),
				('D', 31, 35)


IF OBJECT_ID('tempdb..#Temp') IS NOT NULL BEGIN DROP TABLE #Temp END
SELECT *, ROW_NUMBER() OVER (ORDER BY code) AS ROWID INTO #temp FROM [SUB_tbl_Reports]

DECLARE @RowCount int
SET @RowCount = 1
DECLARE @NumRows int
SELECT @NumRows = (SELECT COUNT(*) FROM [SUB_tbl_Reports])

DECLARE @code varchar(10)
DECLARE @PStart int
DECLARE @PEnd int

WHILE @RowCount <= @NumRows
BEGIN
	SELECT @code = code, @Pstart = Pstart, @PEnd = Pend
	from #temp where ROWID = @RowCount;
	
	 WITH q AS
			(
			SELECT  @Pstart AS num
			UNION ALL
			SELECT num + 1
			FROM q
			WHERE num < @Pend
			)
		insert into [SUB_tbl_Reports_Audit] SELECT [#temp].code, num FROM [#temp], q WHERE ROWID = @RowCount
		OPTION (MAXRECURSION 0)

	SET @RowCount = @RowCount + 1
END

select * from [SUB_tbl_Reports_Audit]
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900