【水晶报表之图片篇-b】 CR 11以下版本动态显示图片(数据库保存图片路径)
版权声明:欢迎转载,但请注明出处 www.cnblogs.com/alone
环境描述:
SqlServer 2000、Crystal Report(水晶报表)XI 以下版本
引语
水晶报表以其强大的功能占距了强大的开发市场,其打印出的报表美观、大方,深得用户喜爱,然而其某些功能上不免有些瑕疵。例如,当数据库中只存放了图片的路径时,当你在设计报表时,没有提供将其打印成图片的功能,可能水晶报表公司也看到了广大使用者的需要,在新近的Crystal Report XI中添加了对此的支持,请参见:http://www.businessobjects.com/products/reporting/crystalreports/formatting.asp,Dynamic image location标题下有详细的Flash功能演示,我就不详细说明了。但Crystal Report XI以下并未提供该功能,用户只能在数据库中使用image字段保存图片、使用第三方的工具或在程序中处理,然而这三种方式都有不足:
1、建立image字段会使数据库文件变得更大,影响了数据库执行效率,而且在特定的情况下,不能使用image字段保存图片,比如用户希望在更新图片时只需将新的图片文件替换掉旧图片时,这个方法就不好用了;
2、使用第三方的工具,参见http://www.crystalkeen.com/tools/cviewimage.htm,以COM组件的方式从数据库中存储的图片路径中提取实际的图片,内嵌于结果集中,提供给Crystal Report。这个方法也有很多不足,比如:不能支持复杂的数据查询;
3、在程序中处理,VB的代码,我没有深入的研究,大概的原理就是循环表中的picture对象,在程序中更改其源位置,这样,在报表生成之前图片就被替换掉了,这种方法当然不用说了,要Coding了,有兴趣的朋友可以研究一下,交流交流。会不会有限制还不清楚,更主要的问题,如果用户只想通过数据库来提供数据源,这个当然不能满足需求了。
参见:[Crystal Report 8]http://support.businessobjects.com/library/kbase/articles/c2014707.asp
[Crystal Report 9]http://support.businessobjects.com/communityCS/FilesAndUpdates/cr9_vb_rdc_loadpic.exe.asp
综上所述,Crystal report XI以下版本对图片的支持是开发人员头痛的事,怎样能够才能方便的使Crystal report支持动态根据数据库路径图片显示呢?本人做了以下研究,下面给出一个简单的应用,希望抛砖引玉,有朋友能将其完善。
解决方案
众所周知,如果数据库中存在一个image字段,在Crystal Report设计报表时使用它是很方便,只需将该字段拖曳到相应的位置,报表在运行时将会从数据库中动态加载图片。如果数据库中并未建立image字段,而是建立了一个字段imgsrc用以保存图片的路径,就不能使用拖曳的方法,怎么解决图片的动态加载呢?通过分析Crystal Report访问image字段和Crystal Report支持从存储过程获取数据源的机制,可以得出以下思路:
编写存储过程,从图片存储的表获取图片的路径,通过使用临时表技术创建一个含image字段的临时表,并使用bcp实用工具加图片导入临时表中,最近通过与临时表关联查询,获得一个包含image字段的数据集。这样,在Crystal Report只需将报表的数据源连接到该存储过程中,在设计时就可直接从该数据集中将image字段拖曳到设计界面了。
下面是实现该存储过程的具体代码,其中的导入图片参考修改了CSDN:邹建 的代码:
drop procedure [dbo].[sp_dynaRptImg]
GO
create proc sp_dynaRptImg
AS
declare @fname_in varchar(1000) --bcp处理应答文件名
,@fsize varchar(20) --要处理的文件的大小
,@m_tbname varchar(50) --临时表名
,@sql varchar(8000)
,@fname varchar(1000) --目录+文件名,处理过程中要使用/覆盖:@filename+_temp
declare @servename varchar(30)
,@username varchar(30)
,@password varchar(30)
SET @servename = @@servername
set @username = 'sa'
set @password ='sa'
--则取得导入文件的大小
create table #pic (img image)
insert #pic select 0x394872
create table #pictt(pic varchar(2000),src image)
insert into #pictt select 'c:\a.jpg',0x394872 --以下4行为插入演示数据
insert into #pictt select 'c:\b.jpg',0x394872
insert into #pictt select 'c:\b.jpg',0x394872
insert into #pictt select 'c:\b.jpg',0x394872
insert into #pictt select 'c:\a.jpg',0x394872
declare cur_1 cursor for select pic from #pictt
open cur_1
fetch cur_1 into @fname
while @@fetch_status = 0
begin
create table #tb(可选名 varchar(20),大小 int
,创建日期 varchar(10),创建时间 varchar(20)
,上次写操作日期 varchar(10),上次写操作时间 varchar(20)
,上次访问日期 varchar(10),上次访问时间 varchar(20),特性 int)
insert into #tb
exec master..xp_getfiledetails @fname
select @fsize=大小 from #tb
drop table #tb
if @fsize is null
begin
print 'file not found'
return
end
--生成数据处理应答文件
set @m_tbname='[##temp'+cast(newid() as varchar(40))+']'
set @sql='select * into '+@m_tbname+' from(
select null as 类型
union all select 0 as 前缀
union all select '+@fsize+' as 长度
union all select null as 结束
union all select null as 格式
) a'
exec(@sql)
select @fname_in=@fname+'_temp'
,@sql='bcp "'+@m_tbname+'" out "'+@fname_in
+'" /S"'+@servename
+case when isnull(@username,'')='' then ''
else '" /U"'+@username end
+'" /P"'+isnull(@password,'')+'" /c'
exec master..xp_cmdshell @sql,no_output
--删除临时表
set @sql='drop table '+@m_tbname
exec(@sql)
--为数据导入准备临时表
set @sql='select top 0 img into '
+@m_tbname+' from #pic'
exec(@sql)
--将数据导入到临时表
set @sql='bcp "'+@m_tbname+'" in "'+@fname
+'" /S"'+@servename
+case when isnull(@username,'')='' then ''
else '" /U"'+@username end
+'" /P"'+isnull(@password,'')
+'" /i"'+@fname_in+'"'
exec master..xp_cmdshell @sql,no_output
--将数据导入到正式表中
set @sql='update #pictt'
+' set src=b.img'
+' from #pictt a,'
+@m_tbname +' b' +' where a.pic =''' + @fname+''''
exec(@sql)
--删除数据处理临时表
set @sql='drop table '+@m_tbname
exec(@sql)
--删除数据处理应答文件
set @sql='del '+@fname_in
exec master..xp_cmdshell @sql,no_output
fetch cur_1 into @fname
end
close cur_1
deallocate cur_1
set @sql='select pic,src from #pictt'
exec(@sql)
set @sql='drop table #pic'
exec(@sql)
set @sql='drop table #pictt'
exec(@sql)
GO
上面的存储过程并不完美,如果能将上面的代码做成函数在存储过程中使用就好了。可能在存储过程中筛选出数据到一个临时表,再更改该表的结构,增加一个image字段,通过函数取得图片,同时更新该字段,再者,还可以尽量不使用游标。这样T-SQL的通用性和性能都会有很大的提升。如哪位朋友有兴趣的话,可以贴上来研究一下。