首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 数据库 > SQL Server >

存储过程:Exec(@s1+@s2+@s3.),因字符数大于8000而被截取了,该如何避免呢?等

2012-02-13 
存储过程:Exec(@s1+@s2+@s3...),因字符数大于8000而被截取了,该如何处理呢?急等@s1,@s2,@s3都被定义varcha

存储过程:Exec(@s1+@s2+@s3...),因字符数大于8000而被截取了,该如何处理呢?急等
@s1,@s2,@s3都被定义varchar(8000)
(@s1+@s2+@s3...)的字符数大于8000,此时执行Exec的操作,那么sql语句会被截取至小等于8000的状态,那么执行时就会出错。我该怎么做才能让这个SQL语句正常的执行呢
看到有说用Text类型的,我declare   @s1   text,确又提示错误,迷茫了

[解决办法]
(@s1+@s2+@s3...)的字符数大于8000,此时执行Exec的操作,那么sql语句会被截取至小等于8000的状态,那么执行时就会出错

-----

EXEC(@S1 + @S2 + @S3)應該不會出錯啊。

邹老大講的“化解字符串不能超过8000的方法”中第一個就是這個方法。


/*--化解字符串不能超过8000的方法

经常有人提到,用动态生成SQL语句的方法处理数据时,处理语句超长,无法处理的问题
下面就讨论这个问题:
--邹建 2003.9(引用请保留此信息)--*/


--方法1. 多个变量处理

--根据查询结果定义变量(实际处理中,应该是估计需要多少个变量,定义足够多的变量个数,多定义变量并不影响处理,下面就多定义了一个)
--生成数据处理临时表
SELECT id=IDENTITY(int,0,1),
g=0,
a=CAST(N ', '+QUOTENAME([name])
+N '=SUM(CASE [name] WHEN N '+QUOTENAME(name,N ' ' ' ')
+N ' THEN [colid] ELSE 0 END) '
as nvarchar(4000))
INTO # FROM syscolumns
WHERE name> N ' '
GROUP BY name

--分组临时表
UPDATE a SET G=id/i
FROM # a,(SELECT i=3800/MAX(LEN(a)) FROM #)b
SELECT MAX(g)+1 as N '需要的变量个数 ' FROM #

DECLARE @0 nvarchar(4000),@1 nvarchar(4000),@2 nvarchar(4000),@3 nvarchar(4000),@4 nvarchar(4000)
SELECT @0=N ' ',@1=N ' ',@2=N ' ',@3=N ' ',@4=N ' '
SELECT
@0=CASE g WHEN 0 THEN @0+a ELSE @0 END,
@1=CASE g WHEN 1 THEN @1+a ELSE @1 END,
@2=CASE g WHEN 2 THEN @2+a ELSE @2 END,
@3=CASE g WHEN 3 THEN @3+a ELSE @3 END,
@4=CASE g WHEN 4 THEN @4+a ELSE @4 END
FROM #
EXEC(N 'SELECT xtype '+@0+@1+@2+@3+@4+N ' FROM syscolumns GROUP BY xtype ')
DROP TABLE #

/*--方法说明

优点:比较灵活,数据量大时只需要增加变量就行了.不用改动其他部分
缺点:要自行估计处理的数据,估计不足就会出错
--*/

[解决办法]
大于8000 我还没有碰到过,不过先收下,以后可以用老大的方法看看.
老大真牛人一个,什么都想过,方法也都有.
多多学习
[解决办法]
估計是你其中某个@s1超過8000了...

exec(@s1+@s2+@s3..)
改成
select len(@s1)
select len(@s2)
select len(@s3)
...看看,是不是有問題
[解决办法]
楼主纯数字ID,是个老人了。
[解决办法]
如果單個沒有超過8000,EXEC(@S1 + @S2 + @S3)不會出錯。
[解决办法]
558047(三个代表万睡!八荣八耻万睡!) ( ) 信誉:86 Blog 加为好友 2007-04-10 09:31:59 得分: 0


select len(@s7),len(@s8),len(@s1),len(@s2),len(@s3),len(@s4),len(@s5),len(@s6)
----------- ----------- ----------- ----------- ----------- ----------- ----------- -----------
3948 3520 4010 4010 4010 4010 4010 4010

(所影响的行数为 1 行)


---------
實際上你定義的變量已經超出范圍了

Declare @S7 varchar(8000), @S8 varchar(8000),@S1 varchar(8000), @S2 varchar(8000), @S3 varchar(8000),@S4 varchar(8000), @S5 varchar(8000), @S6 varchar(8000)

雖然你定義的變量類型為varchar,長度為8000

但是你的ProduceNo的類型是nvarchar,而varchar+nvarchar=nvarchar,nvarchar()最多字符串长度是4000。

這就表明實際上@s1, @s2,@s3,@s4,@s5,@s6已經超出長度了,所以在最好執行EXEC的時候會報錯。


[解决办法]
這就表明實際上@s1, @s2,@s3,@s4,@s5,@s6已經超出長度了,所以在最後執行EXEC的時候會報錯。
[解决办法]
你如果要用varchar;

首先:把所有的 " N '...... ' " 前面的 "N "去除.

然后:把跟nvarchar变量相加的地方.cast(Your_Nvarchar_Var as varchar(NUM))



如: @ProductNo NVarchar(20) 你相加时就得:cast(@ProductNo as varchar(40))

这样肯定可以了.
[解决办法]
Insert TEST
Select B.ProduceNo,A.Dt,AJl,WJl,ASx,WSx,ABlk,WBlk from
(select ProduceNo,
cast(Day(min(ProduceDate)) as Nvarchar(2))+ '- '+cast(Day(max(ProduceDate)) as NVarchar(2)) as dt

---这儿,你用到nvarchar列,在字符串相加时,也得cast( as varchar(...))

exec(....)里面字符串长度可以达100M.不存在8000限制. 只是是你varchar,nvarchar混合相加造成出错.
[解决办法]
在拼結語句的時候,nvarchar全部改為varchar來拼結。

看看這個例子

Create Table TempTEST(TEST Nvarchar(20))
GO
Insert Into TempTEST Select 'ABCDEFGHIJKLMNOPQRST ' From Sysobjects
GO
Declare @S Varchar(8000)
Set @S = ' '
Select @S = @S + TEST From TempTEST
Print Len(@S)
Print DataLength(@S)

GO
Declare @S Varchar(8000)
Set @S = ' '
Select @S = @S + Cast(TEST As Varchar) From TempTEST
Print Len(@S)
Print DataLength(@S)
GO
Drop Table TempTEST
--Result
/*

(影響 328 個資料列)

4000
4000
6560
6560
*/
[解决办法]
/*--化解字符串不能超过8000的方法

经常有人提到,用动态生成SQL语句的方法处理数据时,处理语句超长,无法处理的问题
下面就讨论这个问题:
--邹建 2003.9(引用请保留此信息)--*/

/*-- 测试环境

--以系统表 syscolumns 为测试数据,要求按xtype为列字段,name为行字段,统计colid的和
--要求结果

xtype filedname_1 fieldname_2 ..... fieldname_n
-------- -------------- -------------- -------- --------------
34 0 0 ..... 1
--*/

/*--常规处理方法(不加行数限制会因生成的字符串益出而出错)
set rowcount 10--因为syscolumns的记录较,会导致生成的字符串溢出,所以限制一下行数

declare @s nvarchar(4000)
set @s= ' '
select @s=@s+N ', '+quotename([name])
+N '=sum(case name when '+quotename([name], ' ' ' ')
+N ' then [colid] else 0 end) '
from(select distinct [name] from [syscolumns]) a

set rowcount 0--取消限制
exec(N 'select [xtype] '+@s+N ' from [syscolumns] group by [xtype] ')

/*--问题
不加行数限制时,会因生成的字符串益出而出错
--*/
--*/

/*--方法1. 多个变量处理

--根据查询结果定义变量(实际处理中,应该是估计需要多少个变量,定义足够多的变量个数,多定义变量并不影响处理,下面就多定义了一个)
--生成数据处理临时表
SELECT id=IDENTITY(int,0,1),
g=0,
a=CAST(N ', '+QUOTENAME([name])
+N '=SUM(CASE [name] WHEN N '+QUOTENAME(name,N ' ' ' ')
+N ' THEN [colid] ELSE 0 END) '
as nvarchar(4000))
INTO # FROM syscolumns
WHERE name> N ' '
GROUP BY name

--分组临时表
UPDATE a SET G=id/i
FROM # a,(SELECT i=3800/MAX(LEN(a)) FROM #)b
SELECT MAX(g)+1 as N '需要的变量个数 ' FROM #

DECLARE @0 nvarchar(4000),@1 nvarchar(4000),@2 nvarchar(4000),@3 nvarchar(4000),@4 nvarchar(4000)
SELECT @0=N ' ',@1=N ' ',@2=N ' ',@3=N ' ',@4=N ' '
SELECT
@0=CASE g WHEN 0 THEN @0+a ELSE @0 END,
@1=CASE g WHEN 1 THEN @1+a ELSE @1 END,
@2=CASE g WHEN 2 THEN @2+a ELSE @2 END,
@3=CASE g WHEN 3 THEN @3+a ELSE @3 END,
@4=CASE g WHEN 4 THEN @4+a ELSE @4 END
FROM #
EXEC(N 'SELECT xtype '+@0+@1+@2+@3+@4+N ' FROM syscolumns GROUP BY xtype ')
DROP TABLE #

/*--方法说明

优点:比较灵活,数据量大时只需要增加变量就行了.不用改动其他部分
缺点:要自行估计处理的数据,估计不足就会出错
--*/
--*/

/*--方法2. bcp+isql

--因为要用到bcp+isql,所以需要这些信息
declare @servername sysname,@username sysname,@pwd sysname
select @servername=@@servername --服务器名
,@username=N ' ' --用户名


,@pwd=N ' ' --密码

declare @tbname sysname,@s nvarchar(4000)

--创建数据处理临时表
set @tbname=quotename(N '##temp_ '+cast(newid() as varchar(36)))
set @s=N 'create table '+@tbname+ '(a nvarchar(4000))
insert into '+@tbname+N '
select N ' 'create view '
+stuff(@tbname,2,2,N ' ')
+N ' as
select [xtype] ' '
union all
select N ' ', ' '+quotename([name])+ ' '=sum(case [name] when N ' '
+quotename([name], ' ' ' ' ' ' ' ')
+ ' ' then [colid] else 0 end) ' '
from(select distinct [name] from [syscolumns] where name <> N ' 'xtype ' ')a
union all
select N ' 'from [syscolumns] group by [xtype] ' ' '
exec(@s)

--生成创建视图的文件,注意使用了文件:c:\temp.txt
set @s=N 'bcp " '+@tbname+N ' " out "c:\ '+@tbname+N ' " /S " '
+@servername+N ' " /U " '+@username+N ' " /P " '+@pwd+N ' " /w '
exec master..xp_cmdshell @s,no_output

--调用isql生成数据处理视图
set @s=N 'osql /S " '+@servername
+case
when @username=N ' ' then N ' " /E '
else N ' " /U " '+@username+N ' " /P " '+@pwd+N ' " '
end
+N ' /d " '+db_name()+N ' " /i "c:\ '+@tbname+ ' " '
exec master..xp_cmdshell @s,no_output

--删除临时文件
set @s=N 'del "c:\ '+@tbname+ ' " '
exec master..xp_cmdshell @s,no_output

--调用视图,显示处理结果
set @s=N 'drop table '+@tbname+N '
select * from '+stuff(@tbname,2,2,N ' ')+N '
drop view '+stuff(@tbname,2,2,N ' ')
exec(@s)

/*--方法总结

优点:程序自动处理,不存在判断错误的问题
缺点:复杂,经过的步骤多,容易出错,而且需要一定的操作员权限
--*/
--*/

--/*-- 方法3. 多个变量处理,综合了方法1,2的优点,解决了方法1中需要人为判断,增加变量的问题,排除了方法2,需要权限和过程复杂的问题
DECLARE @sqlhead nvarchar(4000),@sqlend nvarchar(4000)
,@sql1 nvarchar(4000),@sql2 nvarchar(4000),@sql3 nvarchar(4000),@sql4 nvarchar(4000)
,@i int,@ic nvarchar(10)

--生成数据处理临时表
SELECT id=IDENTITY(int,0,1),
g=0,
a=CAST(N ', '
+QUOTENAME([name])
+N '=SUM(CASE [name] WHEN N '
+QUOTENAME(name,N ' ' ' ')
+N ' THEN [colid] ELSE 0 END) '
as nvarchar(4000))
INTO # FROM(
SELECT DISTINCT name FROM [syscolumns] WHERE name> N ' ')a

--分组临时表
UPDATE a SET @i=id/i,g=@i
FROM # a,(SELECT i=3800/MAX(LEN(a)) FROM #)b
SET @ic=@i

--生成数据处理语句
SELECT
@sqlhead=N ' ' ' '
+REPLACE(N 'SELECT [xtype] ',N ' ' ' ',N ' ' ' ' ' ')
+ ' ' ' ',
@sqlend=N ' ' ' '
+REPLACE(N ' FROM [syscolumns] GROUP BY [xtype] ',N ' ' ' ',N ' ' ' ' ' ')
+N ' ' ' ',
@sql1=N ' ',@sql2=N ' ',@sql3=N ' ',@sql4=N ' '
WHILE @ic> =0
SELECT
@sql1=N ',@ '+@ic+N ' nvarchar(4000) '+@sql1,
@sql2=N ',@ '+@ic+N '=N ' ' ' ' '+@sql2,
@sql3=N ',@ '+@ic
+N '=CASE g WHEN '+@ic
+N ' THEN @ '+@ic+N '+a ELSE @ '+@ic
+N ' END '+@sql3,
@sql4=N '+@ '+@ic+@sql4,
@ic=@ic-1
SELECT
@sql1=STUFF(@sql1,1,1,N ' '),
@sql2=STUFF(@sql2,1,1,N ' '),
@sql3=STUFF(@sql3,1,1,N ' '),
@sql4=STUFF(@sql4,1,1,N ' ')



--执行
EXEC(N 'DECLARE '+@sql1+N '
SELECT '+@sql2+N '
SELECT '+@sql3+N ' FROM #
EXEC(N '+@sqlhead+N '+ '+@sql4+N '+N '+@sqlend+N ') ')
--删除临时表
DROP TABLE #

/*--方法总结

总结了前两种方法的优点,自动判断需要处理的变量数
--*/
--*/

[解决办法]
主要是varchar 與nvarchar 前者最大8000,後者最大4000
[解决办法]
LZ你將所有的nvarchar改為varchar,再將N ' 去掉,試下看行不行...
[解决办法]
有一個辦法是,比如
select @s=@s+ ', '+name from T --@s將超過8000,
可以分資料
比如
select @s1=@s1+ ', '+name from T where id between 1 and 100
select @s2=@s2+ ', '+name from T where id between 100 and 200
....
print @s1+@s2+@s3..就這意思啦
[解决办法]
字段类型改为
varchar -> text
nvarchar -> ntext
[解决办法]
如果是 SQL 2005

declare @sql varchar(max)

可容纳 2^31-1 个字符,这个数量级,按每秒钟输入70个字符计,不停地输入10年,大概就可以填满这个变量了。
[解决办法]
SQL 2000 的解决方案:

SQL code
exec('processing')
[解决办法]

不错不错,


热点排行