当你遇到困难时,心中总有一个奇怪的念头——我遇到的怎么都是些这么奇怪的问题!
紧张且匆忙的一天终于过去了。说紧张,因为工作效率和同事比起来实在是太低了,匆忙也就不言而喻!
使用一个不熟悉的开发方式下,对一个要求开发效率的公司里面简直是致命的,上一家公司工作几乎快两年了,一直是Jquery(Ajax)+ Oracle2010;C#里面拼接SQL语句,然后参数化该语句。现在完全不一样了,AjaxPro+SQL Server2008+公司框架+存储过程(动态拼接移到SQL语句了)+ 大量JS代码(使用了公司框架)……
下面讲讲今天拼接的一条存储过程及所遇到的困难。由于存储过程需要配合公司所用的一些东西,所以减少了投机取巧的机会,一定程度上只能由自己完成(虽然得到了不少帮助,但是在一个QQ都会卡掉线的情况下简直太不容易了)。在此感谢一下那些给我提供过帮助的朋友。。。
use TestDB
go
if exists (select * from sysobjects where name='pro_GetPdfTransformTasksList' and type='p')
drop procedure pro_GetPdfTransformTasksList
go
create procedure pro_GetPdfTransformTasksList
@pageSize int = 10,
@pageIndex int = 0,
@RealName nvarchar(100)='',
@IncidentNo int = -1,
@STime datetime='1900-01-01 00:00:00',
@ETime datetime='1900-01-01 00:00:00',
@MoneyS decimal(18,2)=-1,
@MoneyE decimal(18,2)=-1,
@Status int=0,
@Result int=0,
@countRecord int output
--,@countPage int output
AS
declare @sql nvarchar(1000),@sqlTemp nvarchar(2000)
set @sql=N' select p.PT_Guid,p.PT_FileName,p.PT_FileId,p.PT_ProcessName,p.PT_IncidentNo,p.PT_CreateTime,
p.PT_Money,p.PT_UserId,p.PT_UserLoginName,p.PT_UserRealName,p.PT_Status,p.PT_Result,
p.PT_ResultDesc,p.PT_UrgencyDegree,pf.pdfCount from PdfTransformTasks as p
left join (select PT_Guid,count(PF_Guid) pdfCount
from PdfTransformFiles
group by PT_Guid ) as pf
on p.PT_Guid=pf.PT_Guid
where 1=1 '
if((@RealName is not null) and @RealName != '')
begin
set @sql = @sql + ' and p.PT_UserRealName='''+@RealName + ''''
end
if((@IncidentNo is not null) and @IncidentNo!=-1)
begin
set @sql = @sql + ' and p.PT_IncidentNo=' + convert(nvarchar,@IncidentNo)
end
if(@STime is not null and @STime!=convert(datetime,'1900-01-01 00:00:00'))
begin
set @sql = @sql + ' and p.PT_CreateTime>=''' + convert(nvarchar,@STime)+''''
end
if(@ETime is not null and @ETime!=convert(datetime,'1900-01-01 00:00:00'))
begin
set @sql = @sql + ' and p.PT_CreateTime<=''' + convert(nvarchar,@ETime)+''''
end
if(@MoneyS is not null and @MoneyS!=-1)
begin
set @sql = @sql + ' and p.PT_Money>=' + convert(nvarchar,@MoneyS)
end
if(@MoneyE is not null and @MoneyE!=-1)
begin
set @sql = @sql + ' and p.PT_Money<=' + convert(nvarchar,@MoneyE)
end
if(@Status is not null and @Status!=0)
begin
set @sql = @sql + ' and p.PT_Status=' + convert(nvarchar,@Status)
end
if(@Result is not null and @Result!=0)
begin
set @sql = @sql + ' and p.PT_Result=' + convert(nvarchar,@Result)
end
set @sqlTemp=N'select top '+cast(@pageSize as nvarchar(10))+' * from ('+@sql+') as tab '+
' where tab.pt_guid not in (select top '+cast((@pageSize*@pageIndex) as nvarchar(10))+' t.pt_guid from ('+@sql+') as t)'
declare @counttemp int ,@sqltemp2 nvarchar(2000)
set @sqltemp2='select @count1=count(1) from ('+@sqlTemp+') as aaa'
exec sp_executesql @sqltemp2,N'@count1 int out',@counttemp out
set @countRecord=@counttemp
select @countRecord as aaa
exec(@sqlTemp)
/*set @countPage=@countRecord/@pageSize
if(@countRecord%@pageSize<>0)
set @countPage=@countPage+1 */
go
问题一:select convert(datetime,'1900-00-00 00:00:00')
说明:看出问题了么?在比较匆忙的情况下你也许会对错误提示比较抓狂。
问题二:拼接SQL语句中,时间类型转换。如:set @sql = @sql + ' and p.PT_CreateTime<=''' + convert(nvarchar,@ETime)+''''
说明:这儿和Oracle的to_date()函数比较像,千万不要写成了 set @sql = @sql + ' and p.PT_CreateTime<='convert(nvarchar,'' + @ETime+')''',不然,变量“@ETime”始终会出现在你的SQL查询结果错误信息中。
问题三:执行报千奇百怪的错误信息,怎么办?1、存储过程里面exec(@sql)的exec换成print,那么执行结果就可以看到错误信息了,然后把打印出来的sql语句复制到查询窗口里面去,看看详细的错误信息。很多时候都是sql拼接错误,对于新手来说,这个方法比较适用。
学到了什么?
一、沉着冷静,不管遇到什么问题,紧张,急于求成,只会带来负面效果。你要做的就是认真分析,查找错误来源,寻找排错对策。
二、除了问题二里面说到的exec换成print,其实还可以在整段存储过程中其他地方添加print,执行后可以看到SQL语句执行到什么地方出错的,然后就是SQL profile监视工具,使用断点调试配合该工具,非常方便。在程序里面想调试的sql语句前后分别断点,当运行到sql前断点时,清除掉所监视的所有数据,然后程序运行到sql后面的断点,让profile暂停下来,这时就可以看到刚才监视到运行的sql语句了。
三、参见贴出的SQL片段,主要注意在幅初始值给不同类型的参数及标点符号、转义等。
疑问:
一、如果使用动态拼接好的sql语句。例如上面SQL片段中的@sql,因为在拼接好@sql语句后,需要通过执行该语句,才能得到数据总条数,例如:现在需要
select count(*) from (@sql),显然,这样写是不行的,上面在同事的帮助下已经给出了答案,但是我想知道有没有跟好的办法,想想上面就因为一个总条数又定义了 一个nvarchar(2000)的变量,感觉不是很好???