读书人

SQL存储过程 循环VS游标 ●请问

发布时间: 2012-01-18 00:23:26 作者: rapoo

SQL存储过程 循环VS游标 ●请教●
特价图书:bookname,publishername,isbn,codeprice,publishdate,authors字段
books里面:bookid,bookname,isbn,authors,publishername,codeprice,discount,publishdate,gettimes字段
目的是把特价图书表里面的isbn和价格相同的图书导入到books表里面
要求:
books表里面有相同的isbn 和价格 则更新books的一条记录
books表里面有不相同的isbn 和价格 或者没有则插入新数据
特价图书 几万条数据
books 200万条数据


现在有现有的存储过程 是用游标写的.但是很慢
我用循环直接写个 但是比游标还要慢~

请各位高手 帮忙设计一下 高分送出

下面是游标代码

SQL code
ALTER procedure [dbo].[导入图书数据_存储过程] 
as
begin ---------------------存储过程开始


declare mycursor cursor for
select bookname,publishername,isbn,codeprice,publishdate,authors from 特价图书

open mycursor

declare @bookid int,@bookname nvarchar(200),@publishername nvarchar(50),@isbn nvarchar(50), @isbn9 nvarchar(50),
@codeprice money,@publishdate datetime,@authors nvarchar(200),@isbncount int,
@bookid1 int,@countfrombookid int

fetch next from mycursor into @bookname,@publishername,@isbn,@codeprice,@publishdate,@authors

select @bookid=max(bookid) from books
insert WangMingtao(bookid) values(1)
while @@fetch_status = 0
begin ------------------------while循环开始


declare @charstr varchar(11) ----检验ISBN的合法性开始
set @charstr='1234567890X'
declare @i int
declare @isbnstr nvarchar(20)
select @i=1
while @i <=len(@isbn)
begin
set @isbnstr=right(left(@isbn,@i),1)
if charindex(@isbnstr, @charstr)=0
begin
set @isbn=replace(@isbn,@isbnstr,'#')
end
set @i=@i+1
end
set @isbn=replace(@isbn,'#','')

set @isbn9=@isbn
if len(@isbn)=13
begin
set @isbn9=substring(@isbn,4,9)
end
if len(@isbn)=10
begin
set @isbn9=left(@isbn,9)
end
----检验ISBN的合法性结束
print('11')
set @bookid=@bookid+1 ----------------------bookid加一
select @isbncount=count(isbn) from books where left(isbn,9)=@isbn9 and codeprice=@codeprice
print('1')
if @isbncount <> 0
begin ---------如果在books中存在该isbn

update books set status=1,isbn=@isbn where left(isbn,9)=@isbn9 and codeprice=@codeprice
select @bookid1=bookid from books where left(isbn,9)=@isbn9 and codeprice=@codeprice
insert WangMingtao(bookid) values(@bookid1)
select @countfrombookid=count(bookid) from frombook where bookid=@bookid1 and [from]=11

if @countfrombookid <> 0
begin
update frombook set discount=80 where bookid=@bookid1 and [from]=11
end
else
begin
insert into frombook ([from],bookid,stocknum,seat,isupdated,discount) values
(11,@bookid1,5,'0',0,80)
end

end ---------如果在books中存在该isbn
else
begin ---------不存在

insert books(bookid,bookname,isbn,authors,publishername,codeprice,discount,publishdate,gettimes)
values
(@bookid,@bookname,@isbn,@authors,@publishername,@codeprice,80,@publishdate,getdate())
insert WangMingtao(bookid) values(@bookid)
insert frombook([from],bookid,stocknum,seat,isupdated,discount) values
(11,@bookid,5,'0',0,80)
end ---------不存在
fetch next from mycursor into @bookname,@publishername,@isbn,@codeprice,@publishdate,@authors


end------------------------while循环结束
close mycursor
deallocate mycursor

end -----------------存储过程结束






-----------------------
下面是我写的循环代码
SQL code
set ANSI_NULLS ONset QUOTED_IDENTIFIER ONgo-----创建存储过程ALTER procedure [dbo].[导入新书]asbegin ---------------------存储过程开始declare @bookid int,@bookname nvarchar(200),@publishername nvarchar(50),@isbn varchar(50), @isbn9 nvarchar(50), @codeprice money,@publishdate datetime,@authors nvarchar(200),@isbncount int,@booksisbn int,@bookid1 int,@countfrombookid intselect @bookid=max(bookid) from booksdeclare @i 


SQL code
set ANSI_NULLS ONset QUOTED_IDENTIFIER ONgo------自定义函数,检验ISBN的合法性ALTER  function [dbo].[ChkIsbn](@Aisbn nvarchar(50)) returns nvarchar(50)asbegindeclare @charstr varchar(11),@isbn9 nvarchar(50)set @charstr='1234567890X'declare @i intdeclare @isbnstr nvarchar(20)select @i=1while @i<=len(@Aisbn)beginset @isbnstr=right(left(@Aisbn,@i),1)    if charindex(@isbnstr, @charstr)=0       begin   set @Aisbn=replace(@Aisbn,@isbnstr,'#')       endset @i=@i+1endset @Aisbn=replace(@Aisbn,'#','')set  @isbn9=@Aisbnif len(@Aisbn)=13set @isbn9=substring(@Aisbn,4,9)if len(@Aisbn)=10 set @isbn9=left(@Aisbn,9) return @isbn9end


[解决办法]
要那么麻烦么?直接:
这是更新的:
update books set 列1=a.列1,列2=a.列2,列3=a.列 from books b inner jion from book a on a.isbn=b.isbn and ...
这是插入的:
insert into books select 列s from bookfrom a where not exits(select 1 from book where isbn=a.isbn and ...
不行吗?
[解决办法]
既然比较都是用isbn9,为什么不在表放一个isbn9字段?

典型的设计影响性能的例子,用临时表而不用游标和循环能提高一些速度,但是很难达到最优
[解决办法]
上面的from book 和 bookfrom 在楼主的程序里好像是什么 frombook.写快了.
[解决办法]
这两个逻辑干什么硬要集中在一个过程中

实在不爽你可以放在一个sp中,没必要用循环或者游标吧

update books set 列1=a.列1,列2=a.列2,列3=a.列 from books b inner jion from book a on a.isbn=b.isbn

insert into books select 列s from book a where not exits(select 1 from book where isbn=a.isbn)

这就差不多了
[解决办法]
帮顶。
[解决办法]
探讨
我想试下你们说的
但是有个问题 两个表的结构是不一样的
code=SQL]insert into books select bookname,publishername,isbn,codeprice,publishdate,authors from books  select bookname,publishername,isbn,codeprice,publishdate,authors from xinbiao001 where not EXISTS (select * from xinbiao001 where isbn=books.isbn)[[/code]

SQL code消息213,级别16,状态1,第1行
插入错误: 列名或所提供值的数目与表定义不匹配…

[解决办法]
同意一楼的,你为什么不直接更新呢?
另外你的ISDN和价格是索引不?如果是索引,相信会更快吧?


insert into books (isbn,价格) where isbn+价格 not in ( select isbn+价格 from 特价图书 )
update books set ...(需要更新的字段) from books a,特价图书 b where a.isbn=b.isbn and a.价格=b.价格

我觉得这样应该就可以了吧?
[解决办法]
数据库批量处理的时候,尽可能不使用循环或者游标,

你可以部分处理到临时表,然后再进行相关操作。

微软看到这样的处理代码,估计会觉得SQLServer的执行速度还是不够快哦。呵呵。

照这样的存储过程,放在老版本的Informix里,那还真是要命啊。
------解决方案--------------------


随便写了一下,没有SQL我调试,你将就看着吧。

SQL code
create function checkISBN(@isbn nvarchar库
[解决办法]
建立了数据函数[dbo].[ChkIsbn]后,不妨这样来处理:
(请检查一下books, 世纪书缘库存这两张表是否有对isbn,codeprice的索引,如果没有的话,建立索引后速度上会提高很多)
--1)books表里面有相同的isbn 和价格 则更新books的一条记录

update t1
set status=1,isbn=t2.isbn
from books t1, 世纪书缘库存 t2
where left(t1.isbn,9)=dbo.ChkIsbn(t2.isbn)
and t1.codeprice=t2.codeprice

--2)books表里面有不相同的isbn 和价格 或者没有则插入新数据

declare @intMaxBookid int
select @intMaxBookid=max(bookid) from books
declare @tblSpecialBooks table (bookid int identity(1,1),isbn nvarchar(50))
--假定isbn为“世纪书缘库存”的主键,如果是主键为其他字段,则改为其他字段关联
insert into @tblSpecialBooks(isbn)
select isbn
from 世纪书缘库存
where dbo.ChkIsbn(t2.isbn) not in (select distinct left(t1.isbn,9) from books)

insert books(bookid,bookname,isbn,authors,publishername,codeprice,discount,publishdate,gettimes,status)
select @intMaxBookid+t2.bookid,bookname,isbn,authors,publishername,codeprice,discount,publishdate,gettimes,status
from 世纪书缘库存 t1, @tblSpecialBooks t2
where t1.isbn=t2.isbn

[解决办法]
探讨
建立了数据函数[dbo].[ChkIsbn]后,不妨这样来处理:
(请检查一下books, 世纪书缘库存这两张表是否有对isbn,codeprice的索引,如果没有的话,建立索引后速度上会提高很多)
--1)books表里面有相同的isbn 和价格 则更新books的一条记录

update t1
set status=1,isbn=t2.isbn
from books t1, 世纪书缘库存 t2
where left(t1.isbn,9)=dbo.ChkIsbn(t2.isbn)
and t1.codeprice=t2.codeprice

--2)books表里面有不相同的isbn 和价格 或者没有则插入新数据

declare @intMaxBookid int
select @intMaxBookid=max(bookid) from books
declare @tblSpecialBooks table (bookid int identity(1,1),isbn nvarchar(50))
-- 假定isbn为“世纪书缘库存”的主键,如果是主键为其他字段,则改为其他字段关联
insert into @tblSpecialBooks(isbn)
select isbn
from 世纪书缘库存
where dbo.ChkIsbn(t2.isbn) not in (select distinct left(t1.isbn,9) from books)

insert books(bookid,bookname,isbn,authors,publishername,codeprice,discount,publishdate,gettimes,status)
select @intMaxBookid+t2.bookid,bookname,isbn,authors,publishername,codeprice,discount,publishdate,gettimes,status
from 世纪书缘库存 t1, @tblSpecialBooks t2
where t1.isbn=t2.isbn

读书人网 >SQL Server

热点推荐