游标换成循环,,,谢谢
declare Level1 cursor for
select companyid,dptid,dptname,capcode,oldcode,storplace_id,storplace,deptype,years,months,buydate,usedate,chief,chiefcode,examiner,paymethod,
rowid,Capcode,Capname,round(orivalue/qty,2) as price, qty,round(depvalue/qty,2) as depvalue,round(salvalue/qty,2) as salvalue,orivalue,depvalue,memo,usetype,
usercode,username
from VfCapdocA with (nolock)
where doccode=@doccode
select @CardNo=0
open Level1
fetch next from Level1 into @companyid,@dptid,@dptname,@capcode,@oldcode,@storplace_id,@storplace,@deptype,@years,@months,@buydate,@docdate,@chief,@chiefcode,@examiner,
@paymethod,@rowid,@Capcode,@Capname,@price,@digit,@depvalue,@salvalue,@allorivalue,@alldepvalue,@memo,@usetype,@usercode,@username
while @@fetch_status=0
begin
set @i=1
while @i<=@digit
begin
update FaCardNoA
set CardNo=isnull(cardno,0)+1
where Capcode=@Capcode
if @@rowcount=0
begin
insert into FaCardNoA(Capcode,CardNo) values(@Capcode,1)
end
select @CardNo=CardNo from FaCardNoA where Capcode=@Capcode
select @cardid=@Capcode+
case when @CardNo>=1 and @CardNo<=9 then '000'+convert(varchar(1),@CardNo)
when @CardNo>=10 and @CardNo<=99 then '00'+convert(varchar(2),@CardNo)
when @CardNo>=100 and @CardNo<=999 then '0'+convert(varchar(3),@CardNo)
when @cardno>=1000 and @cardno<=9999 then convert(varchar(4),@cardno)
else 'OK'
end
if right(@cardid,2)='OK'
begin
close Level1
deallocate Level1
raiserror('超出编码长度!',16,1)
return
end
if @i=@digit
begin
set @price=isnull(@allorivalue,0)-(@digit-1)*isnull(@price,0)
set @depvalue=isnull(@alldepvalue,0)-(@digit-1)*isnull(@depvalue,0)
end
select @oppocompanyid=isnull(oppocompanyid,''),@oppocompanyname=isnull(oppocompanyname,'')
from fcapdocA_d where rowid=@rowid
exec getxxxx @detailrowid output
--生成子表数据
insert into fCapSubdocA(detailrowid,rowid,cardid,Capcode,Capname,qty,price,orivalue,depvalue,salvalue,netvalue,doccode,flag)
values(@detailrowid,@rowid,@cardid,@Capcode,@Capname,1,@price,@price,@depvalue,@salvalue,isnull(@price,0)-isnull(@depvalue,0),@doccode,
case when @paymethod='估价' then 1 else 0 end)
if @@rowcount=0
begin
close Level1
deallocate Level1
raiserror('更新数据有误!',16,1)
return
end
--生成卡片
insert into facardA(Cardid,oldcode,storplace_id,storplace,companyid,dptid,dptname,capcode,oppocompanyid,oppocompanyname,deptype,years,months,indate,usedate,usestatus,chief,chief_code,examiner,status,CapValue,memo,usetype,rowid,usercode,username
,cardtype)
values(@cardid,@oldcode,@storplace_id,@storplace,@companyid,@dptid,@dptname,@capcode,@oppocompanyid,@oppocompanyname,@deptype,@years,@months,@buydate,@docdate,'使用',@chief,@chiefcode,@examiner,case when @paymethod='估价' then 1 else 0 end,@price,@me
mo,@usetype
,@rowid,@usercode,@username,1)
if @@rowcount=0
begin
close Level1
deallocate Level1
raiserror('更新数据有误!',16,1)
return
end
select @i=@i+1
end
fetch next from Level1 into @companyid,@dptid,@dptname,@capcode,@oldcode,@storplace_id,@storplace,@deptype,@years,@months,@buydate,@docdate,@chief,@chiefcode,@examiner,
@paymethod,@rowid,@Capcode,@Capname,@price,@digit,@depvalue,@salvalue,@allorivalue,@alldepvalue,@memo,@usetype,@usercode,@username
end
close Level1
deallocate Level1
[解决办法]
1. VfCapdocA表与FaCardNoA表是什么关系?一对多的吗?
2. FaCardNoA.CardNo的编码有什么规则?你那样写case语句判断那么多,应该改用Stuff()函数去处理
3. 你获取最大的@cardid,其实不用那么麻烦,自己生成的编号,算出来后还要判断?
4. 更新FaCardNoA, 插入fCapSubdocA, 再插入facardA
update FaCardNoA可以改进,生成@cardid也可以改进
[解决办法]
请问游标换成循环的目的是什么?
游标换成循环对性能提升没有意义.
应换成表关联更新的方式较好喔.
[解决办法]
--#1.用不用游标,先测试一下效率再说:
DECLARE @id INT, @doccode INT
DECLARE cursor_Level1 CURSOR STATIC LOCAL FORWARD_ONLY READ_ONLY--1.定义成这个类型的游标: STATIC LOCAL FORWARD_ONLY READ_ONLY
FOR
SELECT id--2.你游标中的变量太多了,如果可以的话,用主键查询方式代替
FROM dbo.VfCapdocA WITH (NOLOCK)
where doccode=@doccode
OPEN cursor_Level1
FETCH NEXT FROM cursor_Level1 INTO @id
WHILE (@@FETCH_STATUS = 0)
BEGIN
--3.用空循环测试一下你游标的效率
/*
insert into fCapSubdocA
SELECT * FROM VfCapdocA WHERE id = @id--2.你游标中的变量太多了,如果可以的话,用主键查询方式代替
*/
FETCH NEXT FROM cursor_Level1 INTO @id
END
CLOSE cursor_Level1
DEALLOCATE cursor_Level1
--#2.循环的效率,不一定比游标好.需要自己测试一下
--#3.当然了,如果不用游标,直接把所有的逻辑用查询实现,一般来说性能最好.
--总结:游标可用;循环不一定就比游标快,还是要了解一下游标和循环之间的性能差异到底在哪儿。对于楼主的需求,个人推荐可用游标(除非测试#1空循环的性能特别差)
[解决办法]
游标换成循环对性能提升没有意义.
[解决办法]
其实用循环和游标,之所以对性能有影响,根本的原因在于,处理数据的方式,也就是取出1条数据,然后处理,处理完成后,再取出下一条,
如果你的表有1000w条数据,那么就得循环1000w次,效率肯定是非常低的。
同样的,如果单纯的sql语句,之所以性能相对较好的原因在于,他是以集合为单位来处理数据,也就是批处理,一次能把所有的数据都处理好。
当然,有时候,由于业务逻辑非常复杂,可能需要写多个语句,每个语句先把中间的结果插入到一个临时表中,然后最后再对临时表进行处理,这也是一个变通的办法,但尽量不要用游标或者是循环来处理数据,因为效率比较低。
[解决办法]
通常使用游标都是不得已的情况,大部分的时候可以使用迭代来解决游标或者是循环的问题。
具体得看需求,lz这个光是代码,没有需求关系的话,很难进行适当的改写。