SQL Server Forums
Profile | Register | Active Topics | Members | Search | Forum FAQ
 
Register Now and get your question answered!
Username:
Password:
Save Password
Forgot your Password?

 All Forums
 SQL Server 2000 Forums
 Transact-SQL (2000)
 Iteration without cursor
 New Topic  Reply to Topic
 Printer Friendly
Author Previous Topic Topic Next Topic  

karuna
Aged Yak Warrior

581 Posts

Posted - 11/17/2005 :  11:14:29  Show Profile  Send karuna a Yahoo! Message  Reply with Quote
We are using cursor in one of our stored procedure, where we need to iterate through the records to update each record. Is there any better way to iterate through the records without using cursors?

Thanks

Karunakaran

Michael Valentine Jones
Yak DBA Kernel (pronounced Colonel)

USA
7007 Posts

Posted - 11/17/2005 :  11:24:18  Show Profile  Reply with Quote
More than likely there is a better way, but since you didn't post any details at all about what you are trying to do, there is no way for us to answer that question.





CODO ERGO SUM
Go to Top of Page

X002548
Not Just a Number

15586 Posts

Posted - 11/17/2005 :  11:26:40  Show Profile  Reply with Quote
True enough....my esp usb port is clogged..follow the instructions in the hint link in my sig...

How aboput posting the actual code as well

Brett

8-)

Hint: Want your questions answered fast? Follow the direction in this link
http://weblogs.sqlteam.com/brettk/archive/2005/05/25/5276.aspx

Add yourself!
http://www.frappr.com/sqlteam
Go to Top of Page

karuna
Aged Yak Warrior

581 Posts

Posted - 11/17/2005 :  12:21:03  Show Profile  Send karuna a Yahoo! Message  Reply with Quote
Will this help? This is not a full piece of table, but I think its relevent to our discussion.If more info needed let me know.


create table #Temp (LName varchar(255),Cid int,Pid int,PmtId int,CurrentRecord int,TotalRecord int)

insert into #Temp
select  'abc',123,123,7879,NULL,3
union
select 'abc',123,234,8799,NULL,3
union
select 'abc',123,456,987,NULL,3
union
select 'xyz',456,001,234,NULL,4
union
select 'xyz',456,345,1234,NULL,4
union
select 'xyz',456,456,5678,NULL,4
union
select 'xyz',456,789,6789,NULL,4

-- Cursor.

DECLARE UpdateCurrentPage CURSOR FOR         
SELECT CID, LName, PID,PmtId  
FROM #Temp
ORDER BY PmtId -- Selecting the records from table #Temp
        
DECLARE @CID INT        
DECLARE @LName VARCHAR(255)        
DECLARE @PID INT        
DECLARE @IncValue INT  
DECLARE @PmtId INT        
        
SET @IncValue = 0        
        
OPEN UpdateCurrentPage        
        
FETCH NEXT FROM UpdateCurrentPage         
INTO @CID, @LName, @PID,@PmtId  
        
WHILE @@FETCH_STATUS = 0        
BEGIN  
--exec test_kk @PmtID -- This SP I need to call in whatever Iteration logic I use.
 UPDATE #Temp        
 SET @incvalue = CurrentRecord = (case @incvalue when 8 then 1 else @incvalue+1 end)        
 WHERE cid = @cid and lname = @lname and pid = @pid        
        
 SET @incvalue = 0        
     
   FETCH NEXT FROM UpdateCurrentPage         
 INTO @CID, @LName, @PID,@PmtId  
END        
        
CLOSE UpdateCurrentPage        
DEALLOCATE UpdateCurrentPage   


The current result is something like this:

LName      Cid         Pid         PmtId       CurrentRecord TotalRecord 
---------- ----------- ----------- ----------- ------------- ----------- 
abc        123         123         7879        1             3
abc        123         234         8799        1             3
abc        123         456         987         1             3
xyz        456         1           234         1             4
xyz        456         345         1234        1             4
xyz        456         456         5678        1             4
xyz        456         789         6789        1             4


What I need is

LName      Cid         Pid         PmtId       CurrentRecord TotalRecord 
---------- ----------- ----------- ----------- ------------- ----------- 
abc        123         123         7879        1             3
abc        123         234         8799        2             3
abc        123         456         987         3             3
xyz        456         1           234         1             4
xyz        456         345         1234        2             4
xyz        456         456         5678        3             4
xyz        456         789         6789        4             4


The PID and PmtId columns will be unique ones.

Thanks

Karunakaran
Go to Top of Page

Vivaldi
Constraint Violating Yak Guru

USA
298 Posts

Posted - 11/17/2005 :  12:43:19  Show Profile  Reply with Quote
Hmm.

my preferred way to avoid cursors is using a Table type with a seq number (identity column)
and use a while loop to loop the table and perform the cursor like operations if you can't do it in sets.

but, at a quick glance you should be able to do an Update without looping the table. (do it in a set)

________________________________________________

Drinking German Beer... fun.
Listening to an accordian player play ACDC...priceless
Go to Top of Page

Michael Valentine Jones
Yak DBA Kernel (pronounced Colonel)

USA
7007 Posts

Posted - 11/17/2005 :  14:42:57  Show Profile  Reply with Quote
This should do it:


drop table #temp
drop table #temp2
drop table #temp3

go

create table #Temp 
(
	LName varchar(5),
	Cid int,
	Pid int,
	PmtId int,
	CurrentRecord int,
	TotalRecord int
)
create table #Temp2 
(
	Seq	int identity(1,1),
	LName varchar(5),
	Cid int,
	Pid int,
	PmtId int,
	CurrentRecord int,
	TotalRecord int,
)
create table #Temp3 
(
	LName varchar(5),
	Cid int,
	Pid int,
	PmtId int,
	CurrentRecord int,
	TotalRecord int
)

insert into #Temp
select  'abc',123,123,7879,NULL,3
union
select 'abc',123,234,8799,NULL,3
union
select 'abc',123,456,987,NULL,3
union
select 'xyz',456,001,234,NULL,4
union
select 'xyz',456,345,1234,NULL,4
union
select 'xyz',456,456,5678,NULL,4
union
select 'xyz',456,789,6789,NULL,4

-- Load temp table with a row sequence number
insert into #temp2
	(
	LName,
	Cid,
	Pid,
	PmtId,
	CurrentRecord,
	TotalRecord
	)
select
	top 100 percent
	*
from
	#temp
order by
	Cid,
	Pid,
	PmtId

insert into #temp3
select
	a.LName,
	a.Cid,
	a.Pid,
	a.PmtId,
	-- Calculate Current Record Number
	CurrentRecord = a.Seq-b.min_seq+1,
	TotalRecord
from
	#temp2 a
	join
	(
	-- Get Min seq # for each Cid
	select
		top 100 percent
		bb.Cid,
		min_seq = min(bb.seq)
	from
		#temp2 bb
	group by
		bb.Cid
	order by
		bb.Cid
	)b
	on a.Cid = b.Cid	
order by
	a.Cid,
	a.Pid,
	a.PmtId

print '#temp'
select * from #temp
print '#temp3'
select * from #temp3



#temp
LName Cid         Pid         PmtId       CurrentRecord TotalRecord 
----- ----------- ----------- ----------- ------------- ----------- 
abc   123         123         7879        NULL          3
abc   123         234         8799        NULL          3
abc   123         456         987         NULL          3
xyz   456         1           234         NULL          4
xyz   456         345         1234        NULL          4
xyz   456         456         5678        NULL          4
xyz   456         789         6789        NULL          4

(7 row(s) affected)

#temp3
LName Cid         Pid         PmtId       CurrentRecord TotalRecord 
----- ----------- ----------- ----------- ------------- ----------- 
abc   123         123         7879        1             3
abc   123         234         8799        2             3
abc   123         456         987         3             3
xyz   456         1           234         1             4
xyz   456         345         1234        2             4
xyz   456         456         5678        3             4
xyz   456         789         6789        4             4

(7 row(s) affected)







CODO ERGO SUM
Go to Top of Page

ehorn
Flowing Fount of Yak Knowledge

USA
1629 Posts

Posted - 11/17/2005 :  15:05:32  Show Profile  Reply with Quote
select lname,cid,pid,pmtid,
	( select count(cid) from #temp t2 where t2.cid = t1.cid and t2.pid <= t1.pid	) currentRecord,
	totalRecord
from 
	#temp t1
order by 
	lname,cid,pid

Go to Top of Page

blindman
Flowing Fount of Yak Knowledge

USA
2365 Posts

Posted - 11/17/2005 :  15:25:34  Show Profile  Reply with Quote
quote:
my preferred way to avoid cursors is using a Table type with a seq number (identity column)
and use a while loop to loop the table and perform the cursor like operations if you can't do it in sets.
...what makes you think that this is going to be any faster than a cursor? It is not the cursors that are slow, it is using looping (loopy?) logic instead of set-based transactions.
Go to Top of Page

karuna
Aged Yak Warrior

581 Posts

Posted - 11/18/2005 :  00:16:13  Show Profile  Send karuna a Yahoo! Message  Reply with Quote
Thanks for the solutions..
Both solutions from MVJ and ehorn works fine. I'm not sure which is an optimal way...

Since I need to update the currentrecord row in #Temp I added this to ehorn's solution

create table #Temp2
(
	LName varchar(5),
	Cid int,
	Pid int,
	PmtId int,
	CurrentRecord int,
	TotalRecord int
)
insert into #temp2
select lname,cid,pid,pmtid,
	(select count(cid) from #temp t2 where t2.cid = t1.cid and 
t2.pid <= t1.pid) currentRecord,
	totalRecord
from
	#temp t1
order by 
	lname,cid,pid
update #temp
set #temp.currentrecord =  t2.currentrecord from #temp inner join 
#Temp2 t2  on  #temp.lname = t2.lname and #temp.cid = t2.cid and 
#temp.pid=t2.pid and #temp.pmtid=t2.pmtid

Well, thats not the problem atleast for now...I think I failed to explain this part earlier and didnt make it bold or something..

--exec test_kk @PmtID -- This SP I need to call in whatever Iteration logic I use.
 UPDATE #Temp        
 SET @incvalue = CurrentRecord = (case @incvalue when 8 then 1 else @incvalue+1 end)        
 WHERE cid = @cid and lname = @lname and pid = @pid        


The case statement is used in a scenario where the totalrecord is more than 8, in that case after the current record reaches 8, we reset it back to 1. so for 9 records the 9th record will have the value of 1 for currentrecord column and so on...

LName Cid         Pid         PmtId       CurrentRecord TotalRecord 
----- ----------- ----------- ----------- ------------- ----------- 
xyz   456         1           234         1             10
xyz   456         345         1234        2             10
.....
.....
xyz   456         456         5678        8             10
xyz   456         789         6789        1             10
xyz   456         007         9999        2             10


Regarding to the that SP marked bold it is similar to this post here.

http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=57635

Thanks


Karunakaran

Edited by - karuna on 11/18/2005 00:26:10
Go to Top of Page

madhivanan
Premature Yak Congratulator

India
22469 Posts

Posted - 11/18/2005 :  01:31:57  Show Profile  Send madhivanan a Yahoo! Message  Reply with Quote
Also refer point1 here
http://weblogs.sqlteam.com/mladenp/archive/2005/08/01/7421.aspx

Madhivanan

Failing to plan is Planning to fail
Go to Top of Page

karuna
Aged Yak Warrior

581 Posts

Posted - 11/18/2005 :  02:19:38  Show Profile  Send karuna a Yahoo! Message  Reply with Quote
quote:
Originally posted by madhivanan

Also refer point1 here
http://weblogs.sqlteam.com/mladenp/archive/2005/08/01/7421.aspx

Madhivanan

Failing to plan is Planning to fail



When I tried to execute that code I get error on these lines...

SET  @cnt = rank =  case when 
     exists (select top 1 id from @table where id not exists
 (select top 1 id from @table where id=t1.id and count1 > t1.count1)
 then 1


Thanks

Karunakaran

Edited by - karuna on 11/18/2005 02:24:47
Go to Top of Page

madhivanan
Premature Yak Congratulator

India
22469 Posts

Posted - 11/18/2005 :  03:09:26  Show Profile  Send madhivanan a Yahoo! Message  Reply with Quote
Here is a corrected code

  declare @table1 table (id int, name varchar(50))
  insert into @table1
  select null, 'text1' union all
  select null, 'text2' union all
  select null, 'text3' union all
  select null, 'text4'
  select * from @table1 
  declare @inc int
  set @inc = 0

  UPDATE @table1 SET @inc = id = @inc + 1
  select * from @table1 

  declare @table table (id int, diag int, count1 int, rank int)
  insert into @table
  select 1, 42, 75, null union all
  select 1, 49, 50, null union all 
  select 1, 38, 22, null union all
  select 2, 70, 48, null union all
  select 2, 33, 27, null union all
  select 2, 30, 12, null union all
  select 2, 34, 5, null union all
  select 2, 54, 3, null union all
  select 3, 42, 75, null union all
  select 3, 49, 50, null union all 
  select 3, 38, 22, null 

  declare @cnt int
  set @cnt = 0
  UPDATE  t1
  SET  @cnt = rank =  case when 
     exists (select top 1 id from @table where     
	not exists (select top 1 id from @table where id=t1.id and count1 > t1.count1))
     then 1
     else @cnt + 1
     end
  from @table t1
  select * from @table


Madhivanan

Failing to plan is Planning to fail
Go to Top of Page

karuna
Aged Yak Warrior

581 Posts

Posted - 11/18/2005 :  04:03:20  Show Profile  Send karuna a Yahoo! Message  Reply with Quote
quote:
Originally posted by madhivanan

Here is a corrected code

SET  @cnt = rank =  case when
exists (select top 1 id from @table where 
not exists (select top 1 id from @table where id=t1.id and count1 > t1.count1)) then 1


Madhivanan

Failing to plan is Planning to fail


I see that you have closed ")" at the end. Which I also tried, still I got an error.....Now I dont get error in the corrected code of yours?... what was that I overlooked?

Thanks

Karunakaran
Go to Top of Page

madhivanan
Premature Yak Congratulator

India
22469 Posts

Posted - 11/18/2005 :  04:13:36  Show Profile  Send madhivanan a Yahoo! Message  Reply with Quote
Here is the change that you need to do

SET @cnt = rank = case when
exists (select top 1 id from @table where id not exists
(select top 1 id from @table where id=t1.id and count1 > t1.count1))
then 1




Madhivanan

Failing to plan is Planning to fail
Go to Top of Page
  Previous Topic Topic Next Topic  
 New Topic  Reply to Topic
 Printer Friendly
Jump To:
SQL Server Forums © 2000-2009 SQLTeam Publishing, LLC Go To Top Of Page
This page was generated in 0.11 seconds. Powered By: Snitz Forums 2000