SQL 处理超过8000字符~~~
-- =============================================
-- Author: sunbird69
-- Create date: 2007/10/26
-- =============================================
/*
问题描述:
平常有时候会对表中某个字段连成了一个字符串的操作,但varchar(max)最大只能放8000长度的字符串,如果处理超过8000的字符串时,
应该如何处理,下面针对此提供了一个解决方案,以前看过类似的文章,整理了一下。方案可以根据表的状况动态的创建需求变量的个数。
*/
-- 创建测试数据,可以修改变量@rc来改变输入数据大小
if exists(select * from sys.objects where object_id=object_id(N'Tb') and type in (N'u'))
begin
drop table Tb
end
create table Tb
(
Tname varchar(300)
)
-- 设置测试数据
declare @c int,
@rc int
select @c=0,-- 循环变量
@rc=10000-- 设置的行数
while @c<@rc
begin
select @c=@c+1
insert into Tb values('This is a SQL test'+cast(@c as varchar))-- 创建数据
end
declare @i int,-- 每个变量可以存放多少个数据行
@j int-- 整个表需要多少变量来存放所有的数据行
select @i=max(len(Tname)) from Tb-- 获取所以数据行中需求字段长度最大的值
set @i=7800/@i-- 每个变量可以存放的行数,设置为7800,因为在得到的字符串有可能存放间隔符如','等
print @i-- 测试
select @j=count(*)/@i from Tb-- 得到需求变量的个数,设置为7800,因为在其中有可能存放间隔符如','等
print @j-- 测试
if object_id('tempdb..#') is not null-- 创建临时表
begin
drop table #
end
select id=identity(int,0,1),-- 设置一个自增字段,为分组作准备
Tname,-- 需要的字段
gid=0-- 分组初始为0
into # from Tb
update # set gid=id/@i-- 设置分组的值
declare @ds varchar(max),-- 需要字义所以变量的字符串
@hs varchar(max),-- 给需要的所以变量设置初值
@es varchar(max),--
@cs varchar(max),-- 给所以变量逐个设置值
@ts varchar(max),-- print 打印测试
@ic varchar(10),-- 需求变量编号
@ss varchar(max)-- select 测试结果
-- 设置变量的初始值
select @ds='',
@hs='select ',
@cs='',
@ts='',
@ss=''
while @j>=0
begin
select @ic=cast(@j as varchar),-- 转换类型
@j=@j-1,-- 控制循环
@ds='@'+@ic+' varchar(8000),'+@ds,-- 设置需求定义变量字符串
@hs=@hs+'@'+@ic+'='''',',-- 给需要的所以变量设置初值的字符串
@cs='select @'+@ic+'=@'+@ic+'+Tname + '','' from # where gid='+@ic+char(13)+@cs,-- 给需求变量逐个设置值
@ts=@ts+'print '+'@'+@ic+';',-- 打印测试字符串
@ss=@ss+'select '+'@'+@ic+' as content'+@ic+';'-- select 测试字符串
-- @ts='+@'+@ic
end
select @ds='declare '+left(@ds,len(@ds)-1)+char(13),-- 增加定义前缀declare
@hs=left(@hs,len(@hs)-1)+char(13),-- 去多余字符
@cs=left(@cs,len(@cs)-1)-- 去多余字符
print @ds-- 测试
print @hs-- 测试
print @cs-- 测试
print @ts-- 测试
print @ss-- 测试
-- 执行结果测试
exec(@ds+@hs+@cs+@ts+@ss)
欢迎大家来拍砖~~~
[解决办法]
邹老大的例子:
常有人提到,用动态生成SQL语句的方法处理数据时,处理语句超长,无法处理的问题
下面就讨论这个问题:
/*-- 数据测试环境 --*/
if exists (select * from dbo.sysobjects where id = object_id(N "[tb] ") and OBJECTPROPERTY(id, N "IsUserTable ") = 1)
drop table [tb]
GO
create table tb(单位名称 varchar(10),日期 datetime,销售额 int)
insert into tb
select "A单位 ", "2001-01-01 ",100
union all select "B单位 ", "2001-01-02 ",101
union all select "C单位 ", "2001-01-03 ",102
union all select "D单位 ", "2001-01-04 ",103
union all select "E单位 ", "2001-01-05 ",104
union all select "F单位 ", "2001-01-06 ",105
union all select "G单位 ", "2001-01-07 ",106
union all select "H单位 ", "2001-01-08 ",107
union all select "I单位 ", "2001-01-09 ",108
union all select "J单位 ", "2001-01-11 ",109
/*-- 要求结果
日期 A单位 B单位 C单位 D单位 E单位 F单位 G单位 H单位 I单位 J单位
---------- ----- ----- ----- ----- ----- ----- ---- ---- ---- ------
2001-01-01 100 0 0 0 0 0 0 0 0 0
2001-01-02 0 101 0 0 0 0 0 0 0 0
2001-01-03 0 0 102 0 0 0 0 0 0 0
2001-01-04 0 0 0 103 0 0 0 0 0 0
2001-01-05 0 0 0 0 104 0 0 0 0 0
2001-01-06 0 0 0 0 0 105 0 0 0 0
2001-01-07 0 0 0 0 0 0 106 0 0 0
2001-01-08 0 0 0 0 0 0 0 107 0 0
2001-01-09 0 0 0 0 0 0 0 0 108 0
2001-01-11 0 0 0 0 0 0 0 0 0 109
--*/
/*-- 常规处理方法*/
declare @sql varchar(8000)
set @sql= "select 日期=convert(varchar(10),日期,120) "
select @sql=@sql+ ",[ "+单位名称
+ "]=sum(case 单位名称 when " " "+单位名称+ " " " then 销售额 else 0 end) "
from(select distinct 单位名称 from tb) a
exec(@sql+ " from tb group by convert(varchar(10),日期,120) ")
/*-- 问题: 如果单位很多,这时,@SQL的值就会被截断,从而出错.*/
/*--下面给出三种解决办法:--*/
--/*-- 方法1. 多个变量处理
--定义变量,估计需要多少个变量才能保存完所有数据
declare @sql0 varchar(8000),@sql1 varchar(8000)
--,...@sqln varchar(8000)
--生成数据处理临时表
select id=identity(int,0,1),groupid=0
,值= ",[ "+单位名称 + "]=sum(case 单位名称 when " " "
+单位名称+ " " " then 销售额 else 0 end) "
into #temp from(select distinct 单位名称 from tb) a
--分组临时表,判断慨最多多少个单位可以组合成一个不超过8000的字符串,这里取假设为5个
update #temp set groupid=id/5 --5为每组的单位个数
--生成SQL语句处理字符串
--初始化
select @sql0= " "
,@sql1= " "
-- ...
-- ,@sqln
--得到处理字符串
select @sql0=@sql0+值 from #temp where groupid=0 --第一个变量
select @sql1=@sql1+值 from #temp where groupid=1 --第二个变量
--select @sqln=@sqln+值 from #temp where groupid=n --第n个变量
--查询
exec( "select 日期=convert(varchar(10),日期,120) "
+@sql0+@sql1
-- ...+@sqln
+ " from tb group by convert(varchar(10),日期,120)
")
--删除临时表
drop table #temp
/*
优点:比较灵活,数据量大时只需要增加变量就行了.不用改动其他部分
缺点:要自行估计处理的数据,估计不足就会出错
*/
--*/
--/*--方法2. bcp+isql
--因为要用到bcp+isql,所以需要这些信息
declare @servername varchar(250),@username varchar(250),@pwd varchar(250)
select @servername= "zj " --服务器名
,@username= " " --用户名
,@pwd= " " --密码
declare @tbname varchar(50),@sql varchar(8000)
--创建数据处理临时表
set @tbname= "[##temp_ "+convert(varchar(40),newid())+ "] "
set @sql= "create table "+@tbname+ "(值 varchar(8000))
insert into "+@tbname+ " values( " "create view "
+stuff(@tbname,2,2, " ")+ " as
select 日期=convert(varchar(10),日期,120) " ") "
exec(@sql)
set @sql= "insert into "+@tbname+ "
select " ",[ " "+单位名称+ " "]=sum(case 单位名称 when " " " " " "
+单位名称+ " " " " " " then 销售额 else 0 end) " "
from(select distinct 单位名称 from tb) a "
exec(@sql)
set @sql= "insert into "+@tbname+ "
values( " "from tb group by convert(varchar(10),日期,120) " ") "
exec(@sql)
--生成创建视图的文件,注意使用了文件:c:\temp.txt
set @sql= "bcp " "+@tbname+ "" out "c:\temp.txt" /S" "
+@servername+ "" /U" "+@username+ "" /P" "+@pwd+ "" /c "
exec master..xp_cmdshell @sql
--删除临时表
set @sql= "drop table "+@tbname
exec(@sql)
--调用isql生成数据处理视图
set @tbname=stuff(@tbname,2,2, " ")
set @sql= "isql /S" "+@servername
+case @username when " " then "" /E " else "" /U" "+@username+ "" /P" "+@pwd+ "" " end
+ " /d" "+db_name()+ "" /i"c:\temp.txt" "
exec master..xp_cmdshell @sql
--调用视图,显示处理结果
set @sql= "select * from "+@tbname+ "
drop view "+@tbname
exec(@sql)
/*
优点:程序自动处理,不存在判断错误的问题
缺点:复杂,经过的步骤多,容易出错,而且需要一定的操作员权限
*/
--*/
--/*-- 方法3. 多个变量处理,综合了方法1及方法2的优点, 解决了方法1中需要人为判断的问题,自动根据要处理的数据量进行变量定义,同时又避免了方法2的繁琐
declare @sqlhead varchar(8000),@sqlend varchar(8000)
,@sql1 varchar(8000),@sql2 varchar(8000),@sql3 varchar(8000),@sql4 varchar(8000)
,@i int,@ic varchar(20)
--生成数据处理临时表
select id=identity(int,0,1),gid=0
,a= ",[ "+单位名称 + "]=sum(case 单位名称 when " " "
+单位名称+ " " " then 销售额 else 0 end) "
into # from(select distinct 单位名称 from tb) a
--判断需要多少个变量来处理
select @i=max(len(a)) from #
print @i
set @i=7800/@i
--分组临时表
update # set gid=id/@i
select @i=max(gid) from #
--生成数据处理语句
select @sqlhead= " " "select 日期=convert(varchar(10),日期,120) " " "
,@sqlend= " " " from tb group by convert(varchar(10),日期,120) " " "
,@sql1= " ",@sql2= "select ",@sql3= " ",@sql4= " "
while @i >=0
select @ic=cast(@i as varchar),@i=@i-1
,@sql1= "@ "+@ic+ " varchar(8000), "+@sql1
,@sql2=@sql2+ "@ "+@ic+ "= " " " ", "
,@sql3= "select @ "+@ic+ "=@ "+@ic+ "+a from # where gid= "+@ic
+char(13)+@sql3
,@sql4=@sql4+ ",@ "+@ic
select @sql1= "declare "+left(@sql1,len(@sql1)-1)+char(13)
,@sql2=left(@sql2,len(@sql2)-1)+char(13)
,@sql3=left(@sql3,len(@sql3)-1)
,@sql4=substring(@sql4,2,8000)
--执行
exec( @sql1+@sql2+@sql3+ "
exec( "+@sqlhead+ "+ "+@sql4+ "+ "+@sqlend+ ") "
)
--删除临时表
drop table #
--*/
方法3中,关键要做修改的是下面两句,其他基本上不用做改变:
--生成数据处理临时表,修改a=后面的内容为相应的处理语句
select id=identity(int,0,1),gid=0
,a= ",[ "+code+ "]=sum(case b.c_code when " " "
+code+ " " " then b.value else 0 end) "
into # from #Class
--生成数据处理语句,将@sqlhead,@sqlend赋值为相应的处理语句头和尾
select @sqlhead= " " "select a.id,a.name,a.code " " "
,@sqlend= " " " from #Depart a,#Value b where a.Code=b.d_Code group by a.id,a.code,a.name " " "
,@sql1= " ",@sql2= "select ",@sql3= " ",@sql4= " "
[解决办法]
但varchar(max)最大只能放8000长度的字符串
-----------------------------------------------
汗!LZ不知道是从那里引用的,很多人不会使用varchar(max),所以认为最大只能放8000长度的字符串
[解决办法]
好贴
记一下
[解决办法]
用exec(@s+@s2)
----------
楼主大概是说的显示结果集吧。。好像7998个字符
max支持2的31次方减1的字节数,大小就2G
[解决办法]
都 varchar(max) 了,没必要那么复杂啦,2G的字符,够不停地输入好几年了
2000情况下,我宁可用一个exec('...')写完,也不会用@1+@2+...+@n来突破8000限制。