--------
[w_no] [char] (7),
[c_no] [char] (8),
[attr] [char] (60),
[other_field_to_update] [char] (60)
tb2
--------
[w_no] [char] (7),
[c_no] [char] (8),
[serial] [char] (2),
[other_field_to_update] [char] (60)
tb1里的attr是一个长度不定的字符串,但是长度肯定是偶数,比如‘01020304’,根据w_no+c_no+serial(将attr两位、两位取出来),和tb2形成一个一对多的关系。
现在的任务就是要将tb1里的每一条记录(每条记录中又有若干项,根据attr的长度而定)在tb2里面搜索一遍,如果找到匹配的记录就将tb1中的一些字段更新到tb2中,并且将tb2中的一些字段信息更新到tb1中。
我的代码如下
DECLARE @w_no char(7),
@c_no char(8),
@serial char(2),
@attr varchar(60),
@serial_count int,
@i int,
@j int
set @i=1
WHILE @i<=(select count(*) from tb1)
BEGIN
SET @w_no=(select w_no from tb1 where id=@i)
SET @c_no=(select c_no from tb1 where id=@i)
SET @serial=(select serial from tb1 where id=@i)
SET @attr=(select rtrim(attr) from tb1 where id=@i)
SET @serial_count=len(@attr/2)
SET @j=1
WHILE @j<=@serial_count
BEGIN
IF exists(select 0 from tb2 where w_no=@w_no and c_no=@c_no and serial=substring(@attr,(@j*2-1),2) and pri_tag='V')
BEGIN
update tb2
set serial_kd=@serial
where w_no=@w_no and c_no=@c_no and serial=substring(@attr,(@j*2-1),2) and pri_tag='V'
update tb1
set ursach_t_a='T',u_teilenr=(select pnr1+pnr2+pnr3+pnr4+pnr5+pnr6 from tb2 where w_no=@w_no and c_no=@c_no and serial=substring(@attr,(@j*2-1),2) and pri_tag='V')
where id=@i
BREAK
END
set @j=@j+1
END
set @i=@i+1
END
主表大概5W条记录,游标我也用过,执行效率都比较低,大概要半个小时才能完成更新。有没有效率更高一点的代码,谢谢大家
14 个解决方案
#1
使用游标的话,效率肯定会低的
#2
循环或者游标逐条处理,不慢才怪.
#3
你说了等于没说么,我就是知道游标效率低,所以问有没有好办法!
#4
--就楼主自己的处理过程而言,本身就有很多不合理的地方
DECLARE @w_no char(7),
@c_no char(8),
@serial char(2),
@attr varchar(60),
@serial_count int,
@i int,
@j int
declare @n int
select @i=1,@n=count(*) from tb1
WHILE @i<=@n --(select count(*) from tb1)
BEGIN
/*
SET @w_no=(select w_no from tb1 where id=@i)
SET @c_no=(select c_no from tb1 where id=@i)
SET @serial=(select serial from tb1 where id=@i)
SET @attr=(select rtrim(attr) from tb1 where id=@i)
SET @serial_count=len(@attr/2)
SET @j=1
*/
--每查一次,就要扫描一次表,其实一次就可以查出来了
select @w_no=w_no,
@c_no=c_no,
@serial=serial,
@attr=rtrim(attr),
@serial_count=len(@attr/2),
@j=1
from tb1 where id=@i
DECLARE @w_no char(7),
@c_no char(8),
@serial char(2),
@attr varchar(60),
@serial_count int,
@i int,
@j int
declare @n int
select @i=1,@n=count(*) from tb1
WHILE @i<=@n --(select count(*) from tb1)
BEGIN
/*
SET @w_no=(select w_no from tb1 where id=@i)
SET @c_no=(select c_no from tb1 where id=@i)
SET @serial=(select serial from tb1 where id=@i)
SET @attr=(select rtrim(attr) from tb1 where id=@i)
SET @serial_count=len(@attr/2)
SET @j=1
*/
--每查一次,就要扫描一次表,其实一次就可以查出来了
select @w_no=w_no,
@c_no=c_no,
@serial=serial,
@attr=rtrim(attr),
@serial_count=len(@attr/2),
@j=1
from tb1 where id=@i
#5
最关键的是楼主并没有说清楚具体要怎么处理,所以上面的回复也只是解决部分问题.
在楼主的代码中,循环分拆更新是检测到一个值就终止当前的分拆搜索,似乎与"如果找到匹配的记录就将tb1中的一些字段更新到tb2中,并且将tb2中的一些字段信息更新到tb1中。"
不太符合,是否难保证attr在tb2中只有<=1个匹配的?
在楼主的代码中,循环分拆更新是检测到一个值就终止当前的分拆搜索,似乎与"如果找到匹配的记录就将tb1中的一些字段更新到tb2中,并且将tb2中的一些字段信息更新到tb1中。"
不太符合,是否难保证attr在tb2中只有<=1个匹配的?
#6
--如果只是根据楼主给出的代码来改写处理,只需要两个更新语句就OK了,根本不用分拆
update b
set serial_kd=a.serial
from tb1 a,tb2 b
where a.w_no=b.w_no
and a.c_no=b.c_no
and b.pri_tag='V'
and charindex(b.serial,a.attr)%2=1
update a
set ursach_t_a='T',u_teilenr=b.pnr1+b.pnr2+b.pnr3+b.pnr4+b.pnr5+b.pnr6
from tb1 a,tb2 b
where a.w_no=b.w_no
and a.c_no=b.c_no
and b.pri_tag='V'
and charindex(b.serial,a.attr)%2=1
update b
set serial_kd=a.serial
from tb1 a,tb2 b
where a.w_no=b.w_no
and a.c_no=b.c_no
and b.pri_tag='V'
and charindex(b.serial,a.attr)%2=1
update a
set ursach_t_a='T',u_teilenr=b.pnr1+b.pnr2+b.pnr3+b.pnr4+b.pnr5+b.pnr6
from tb1 a,tb2 b
where a.w_no=b.w_no
and a.c_no=b.c_no
and b.pri_tag='V'
and charindex(b.serial,a.attr)%2=1
#7
如果b.serial='11',a.attr='011011',用charindex(b.serial,a.attr)%2=1就会产生错误。
我的数据库中的attr字符串编排是两位、两位的按照大小排列,但是出现哪两个是不确定的。
我刚才试了一下用Fast_forward游标将tb1中的w_no,c_no,attr拆分到一个关系表,和tb1是一对多的关系,5秒就可以完成,然后通过联结更新两个表的内容,好像效率还可以。
这样的数据结构是不是很不合理,以前的人设计的,准备在当中加一个关系表。
我的数据库中的attr字符串编排是两位、两位的按照大小排列,但是出现哪两个是不确定的。
我刚才试了一下用Fast_forward游标将tb1中的w_no,c_no,attr拆分到一个关系表,和tb1是一对多的关系,5秒就可以完成,然后通过联结更新两个表的内容,好像效率还可以。
这样的数据结构是不是很不合理,以前的人设计的,准备在当中加一个关系表。
#8
--确实忽略了那个问题,那可以分拆到临时表处理
--一次性分拆,效率应该比游标好
select top 30 id=identity(int,0,1) into # from sysobjects a,sysobjects b
select a.id,attr=substring(attr,b.id*2+1,2) into #1
from tb1 a,# b
where len(attr)/2>=b.id
and exists( select * from tb2 --这个条件可以初步限制只处理符合条件的数据,这样分拆处理会慢一些,但后面的处理会快一些,是否加上,你可以根据实际情况取舍
where a.w_no=w_no
and a.c_no=c_no
and pri_tag='V'
and charindex(serial,a.attr)>0)
update b
set serial_kd=a.serial
from tb1 a,tb2 b,#1 aa
where a.w_no=b.w_no
and a.c_no=b.c_no
and b.pri_tag='V'
and b.serial=aa.attr
and a.id=aa.id
update a
set ursach_t_a='T',u_teilenr=b.pnr1+b.pnr2+b.pnr3+b.pnr4+b.pnr5+b.pnr6
from tb1 a,tb2 b,#1 aa
where a.w_no=b.w_no
and a.c_no=b.c_no
and b.pri_tag='V'
and b.serial=aa.attr
and a.id=aa.id
drop table #,#1
--一次性分拆,效率应该比游标好
select top 30 id=identity(int,0,1) into # from sysobjects a,sysobjects b
select a.id,attr=substring(attr,b.id*2+1,2) into #1
from tb1 a,# b
where len(attr)/2>=b.id
and exists( select * from tb2 --这个条件可以初步限制只处理符合条件的数据,这样分拆处理会慢一些,但后面的处理会快一些,是否加上,你可以根据实际情况取舍
where a.w_no=w_no
and a.c_no=c_no
and pri_tag='V'
and charindex(serial,a.attr)>0)
update b
set serial_kd=a.serial
from tb1 a,tb2 b,#1 aa
where a.w_no=b.w_no
and a.c_no=b.c_no
and b.pri_tag='V'
and b.serial=aa.attr
and a.id=aa.id
update a
set ursach_t_a='T',u_teilenr=b.pnr1+b.pnr2+b.pnr3+b.pnr4+b.pnr5+b.pnr6
from tb1 a,tb2 b,#1 aa
where a.w_no=b.w_no
and a.c_no=b.c_no
and b.pri_tag='V'
and b.serial=aa.attr
and a.id=aa.id
drop table #,#1
#9
up
#10
up
#11
谢谢邹建大侠,分拆效率是高了很多。
但是每条记录分拆后会多一条记录,我需要使用 DELETE #1 where attr='' 来删除。
另外我对这个sql语句还不是很明白,select list里面使用[字段名]=表达式是如何工作的,希望能提供一些例子和参考。
但是每条记录分拆后会多一条记录,我需要使用 DELETE #1 where attr='' 来删除。
另外我对这个sql语句还不是很明白,select list里面使用[字段名]=表达式是如何工作的,希望能提供一些例子和参考。
#12
我觉得有些问题看实际情况而定,如果一定要整张表对比过去,用皱大哥的效率高,但是如果是频繁对比更新的话,我看可能要建触发器什么,有针对性地去检查更新,才是最快的。
#13
--误用了等号,改一下就不存在分拆后多一条记录的问题了.
select top 30 id=identity(int,0,1) into # from sysobjects a,sysobjects b
select a.id,attr=substring(attr,b.id*2+1,2) into #1
from tb1 a,# b
where len(attr)/2>b.id --误用了等号
and exists( select * from tb2 --这个条件可以初步限制只处理符合条件的数据,这样分拆处理会慢一些,但后面的处理会快一些,是否加上,你可以根据实际情况取舍
where a.w_no=w_no
and a.c_no=c_no
and pri_tag='V'
and charindex(serial,a.attr)>0)
select top 30 id=identity(int,0,1) into # from sysobjects a,sysobjects b
select a.id,attr=substring(attr,b.id*2+1,2) into #1
from tb1 a,# b
where len(attr)/2>b.id --误用了等号
and exists( select * from tb2 --这个条件可以初步限制只处理符合条件的数据,这样分拆处理会慢一些,但后面的处理会快一些,是否加上,你可以根据实际情况取舍
where a.w_no=w_no
and a.c_no=c_no
and pri_tag='V'
and charindex(serial,a.attr)>0)
#14
要知道,分拆的工作原理,你可以把所有的列都显示出来,看看得到什么结果来分析.
#1
使用游标的话,效率肯定会低的
#2
循环或者游标逐条处理,不慢才怪.
#3
你说了等于没说么,我就是知道游标效率低,所以问有没有好办法!
#4
--就楼主自己的处理过程而言,本身就有很多不合理的地方
DECLARE @w_no char(7),
@c_no char(8),
@serial char(2),
@attr varchar(60),
@serial_count int,
@i int,
@j int
declare @n int
select @i=1,@n=count(*) from tb1
WHILE @i<=@n --(select count(*) from tb1)
BEGIN
/*
SET @w_no=(select w_no from tb1 where id=@i)
SET @c_no=(select c_no from tb1 where id=@i)
SET @serial=(select serial from tb1 where id=@i)
SET @attr=(select rtrim(attr) from tb1 where id=@i)
SET @serial_count=len(@attr/2)
SET @j=1
*/
--每查一次,就要扫描一次表,其实一次就可以查出来了
select @w_no=w_no,
@c_no=c_no,
@serial=serial,
@attr=rtrim(attr),
@serial_count=len(@attr/2),
@j=1
from tb1 where id=@i
DECLARE @w_no char(7),
@c_no char(8),
@serial char(2),
@attr varchar(60),
@serial_count int,
@i int,
@j int
declare @n int
select @i=1,@n=count(*) from tb1
WHILE @i<=@n --(select count(*) from tb1)
BEGIN
/*
SET @w_no=(select w_no from tb1 where id=@i)
SET @c_no=(select c_no from tb1 where id=@i)
SET @serial=(select serial from tb1 where id=@i)
SET @attr=(select rtrim(attr) from tb1 where id=@i)
SET @serial_count=len(@attr/2)
SET @j=1
*/
--每查一次,就要扫描一次表,其实一次就可以查出来了
select @w_no=w_no,
@c_no=c_no,
@serial=serial,
@attr=rtrim(attr),
@serial_count=len(@attr/2),
@j=1
from tb1 where id=@i
#5
最关键的是楼主并没有说清楚具体要怎么处理,所以上面的回复也只是解决部分问题.
在楼主的代码中,循环分拆更新是检测到一个值就终止当前的分拆搜索,似乎与"如果找到匹配的记录就将tb1中的一些字段更新到tb2中,并且将tb2中的一些字段信息更新到tb1中。"
不太符合,是否难保证attr在tb2中只有<=1个匹配的?
在楼主的代码中,循环分拆更新是检测到一个值就终止当前的分拆搜索,似乎与"如果找到匹配的记录就将tb1中的一些字段更新到tb2中,并且将tb2中的一些字段信息更新到tb1中。"
不太符合,是否难保证attr在tb2中只有<=1个匹配的?
#6
--如果只是根据楼主给出的代码来改写处理,只需要两个更新语句就OK了,根本不用分拆
update b
set serial_kd=a.serial
from tb1 a,tb2 b
where a.w_no=b.w_no
and a.c_no=b.c_no
and b.pri_tag='V'
and charindex(b.serial,a.attr)%2=1
update a
set ursach_t_a='T',u_teilenr=b.pnr1+b.pnr2+b.pnr3+b.pnr4+b.pnr5+b.pnr6
from tb1 a,tb2 b
where a.w_no=b.w_no
and a.c_no=b.c_no
and b.pri_tag='V'
and charindex(b.serial,a.attr)%2=1
update b
set serial_kd=a.serial
from tb1 a,tb2 b
where a.w_no=b.w_no
and a.c_no=b.c_no
and b.pri_tag='V'
and charindex(b.serial,a.attr)%2=1
update a
set ursach_t_a='T',u_teilenr=b.pnr1+b.pnr2+b.pnr3+b.pnr4+b.pnr5+b.pnr6
from tb1 a,tb2 b
where a.w_no=b.w_no
and a.c_no=b.c_no
and b.pri_tag='V'
and charindex(b.serial,a.attr)%2=1
#7
如果b.serial='11',a.attr='011011',用charindex(b.serial,a.attr)%2=1就会产生错误。
我的数据库中的attr字符串编排是两位、两位的按照大小排列,但是出现哪两个是不确定的。
我刚才试了一下用Fast_forward游标将tb1中的w_no,c_no,attr拆分到一个关系表,和tb1是一对多的关系,5秒就可以完成,然后通过联结更新两个表的内容,好像效率还可以。
这样的数据结构是不是很不合理,以前的人设计的,准备在当中加一个关系表。
我的数据库中的attr字符串编排是两位、两位的按照大小排列,但是出现哪两个是不确定的。
我刚才试了一下用Fast_forward游标将tb1中的w_no,c_no,attr拆分到一个关系表,和tb1是一对多的关系,5秒就可以完成,然后通过联结更新两个表的内容,好像效率还可以。
这样的数据结构是不是很不合理,以前的人设计的,准备在当中加一个关系表。
#8
--确实忽略了那个问题,那可以分拆到临时表处理
--一次性分拆,效率应该比游标好
select top 30 id=identity(int,0,1) into # from sysobjects a,sysobjects b
select a.id,attr=substring(attr,b.id*2+1,2) into #1
from tb1 a,# b
where len(attr)/2>=b.id
and exists( select * from tb2 --这个条件可以初步限制只处理符合条件的数据,这样分拆处理会慢一些,但后面的处理会快一些,是否加上,你可以根据实际情况取舍
where a.w_no=w_no
and a.c_no=c_no
and pri_tag='V'
and charindex(serial,a.attr)>0)
update b
set serial_kd=a.serial
from tb1 a,tb2 b,#1 aa
where a.w_no=b.w_no
and a.c_no=b.c_no
and b.pri_tag='V'
and b.serial=aa.attr
and a.id=aa.id
update a
set ursach_t_a='T',u_teilenr=b.pnr1+b.pnr2+b.pnr3+b.pnr4+b.pnr5+b.pnr6
from tb1 a,tb2 b,#1 aa
where a.w_no=b.w_no
and a.c_no=b.c_no
and b.pri_tag='V'
and b.serial=aa.attr
and a.id=aa.id
drop table #,#1
--一次性分拆,效率应该比游标好
select top 30 id=identity(int,0,1) into # from sysobjects a,sysobjects b
select a.id,attr=substring(attr,b.id*2+1,2) into #1
from tb1 a,# b
where len(attr)/2>=b.id
and exists( select * from tb2 --这个条件可以初步限制只处理符合条件的数据,这样分拆处理会慢一些,但后面的处理会快一些,是否加上,你可以根据实际情况取舍
where a.w_no=w_no
and a.c_no=c_no
and pri_tag='V'
and charindex(serial,a.attr)>0)
update b
set serial_kd=a.serial
from tb1 a,tb2 b,#1 aa
where a.w_no=b.w_no
and a.c_no=b.c_no
and b.pri_tag='V'
and b.serial=aa.attr
and a.id=aa.id
update a
set ursach_t_a='T',u_teilenr=b.pnr1+b.pnr2+b.pnr3+b.pnr4+b.pnr5+b.pnr6
from tb1 a,tb2 b,#1 aa
where a.w_no=b.w_no
and a.c_no=b.c_no
and b.pri_tag='V'
and b.serial=aa.attr
and a.id=aa.id
drop table #,#1
#9
up
#10
up
#11
谢谢邹建大侠,分拆效率是高了很多。
但是每条记录分拆后会多一条记录,我需要使用 DELETE #1 where attr='' 来删除。
另外我对这个sql语句还不是很明白,select list里面使用[字段名]=表达式是如何工作的,希望能提供一些例子和参考。
但是每条记录分拆后会多一条记录,我需要使用 DELETE #1 where attr='' 来删除。
另外我对这个sql语句还不是很明白,select list里面使用[字段名]=表达式是如何工作的,希望能提供一些例子和参考。
#12
我觉得有些问题看实际情况而定,如果一定要整张表对比过去,用皱大哥的效率高,但是如果是频繁对比更新的话,我看可能要建触发器什么,有针对性地去检查更新,才是最快的。
#13
--误用了等号,改一下就不存在分拆后多一条记录的问题了.
select top 30 id=identity(int,0,1) into # from sysobjects a,sysobjects b
select a.id,attr=substring(attr,b.id*2+1,2) into #1
from tb1 a,# b
where len(attr)/2>b.id --误用了等号
and exists( select * from tb2 --这个条件可以初步限制只处理符合条件的数据,这样分拆处理会慢一些,但后面的处理会快一些,是否加上,你可以根据实际情况取舍
where a.w_no=w_no
and a.c_no=c_no
and pri_tag='V'
and charindex(serial,a.attr)>0)
select top 30 id=identity(int,0,1) into # from sysobjects a,sysobjects b
select a.id,attr=substring(attr,b.id*2+1,2) into #1
from tb1 a,# b
where len(attr)/2>b.id --误用了等号
and exists( select * from tb2 --这个条件可以初步限制只处理符合条件的数据,这样分拆处理会慢一些,但后面的处理会快一些,是否加上,你可以根据实际情况取舍
where a.w_no=w_no
and a.c_no=c_no
and pri_tag='V'
and charindex(serial,a.attr)>0)
#14
要知道,分拆的工作原理,你可以把所有的列都显示出来,看看得到什么结果来分析.