zoukankan      html  css  js  c++  java
  • 大数据量导出Excel 待测试

     

    set ANSI_NULLS ON
    set QUOTED_IDENTIFIER ON
    go


    /*--数据导出EXCEL

    导出查询中的数据到Excel,包含字段名,文件为真正的Excel文件
    如果文件不存在,将自动创建文件
    如果表不存在,将自动创建表
    基于通用性考虑,仅支持导出标准数据类型
    --Modify
    1、修改邹建的错误:关于provider的书写
    在openrowset时为database
    在ADODb.connection.open时为data source,一个很不容易找到的错误,否则0x80004005 Microsoft JET Database Engine 不能执行选定查询
    2、执行过程过长时,中途无法取消
    3、一些限制
    --Jet SQL无法修改列名,应使用ADOX.Catagory
    --SQLServer2005索引最大为1284 bytes,order by 最大为8060 bytes
    --grant exec分配不了权限
    4、要对@varQuerySQL中结果集排序,请在@varOrderBy指定结果集中的列,存储过程会按此排序,不要再在@varQuerySQL中再排序

    --邹建 2003.10(引用请保留此信息)--*/


    /*--调用示例--

    --表的联合
    p_QueryToExcel @varQuerySQL= 'select top 65000 A.* from a inner join B on A.a1=B.a1'
    ,@varExcelFullPath= 'E:\aa21.xls',@varSheetName= 'sheet'

    select * from liupeng --256003
    --102400条记录
    --时间:
    --@varQuerySQL没有order by TopName,Identitier
    1:50,1:21, 1:55, 1:27(加索引), 1:34(加索引)
    --@varQuerySQL有order by
    大于9:00
    --Select语句列必须带函数的列必须有别名
    p_QueryToExcel @varQuerySQL= 'select MetaID as 标识,Title as 书名,Creator as 作者,Publisher as 出版者,Price as 单价,CopyNum as 复本数,Identitier as 分类号,TopName as 类目,issuedate as 出版时间,ISBN,publishdate as 公布时间,(case
    when IsRef= 0 then ''否''
    when IsRef = 1 then ''是''
    else '''' end ) as 是否教参
    from [liupeng]
    where CategoryTypeID=1 ',@varExcelFullPath= 'E:\aa3.xls',@varSheetName= 'sheet'

    select count(*) from ast_document --334138
    --102400条记录
    --时间:
    --@varQuerySQL没有order by TopName,Identitier
    2:00, 1:10, 1:27, 1:21, 1:20

    p_QueryToExcel @varQuerySQL=' select top 2000 MetaID as 标识,TopIdentitier,DocID,Title,Creator,Publisher,Price,CopyNum,Identitier,TopName,substring(convert(varchar, issuedate, 20), 1, 7) as 出版日期,ISBN,substring(convert(varchar,publishdate, 20), 1, 10) as 发布日期,(case
    when IsRef= 0 then''否''
    when IsRef = 1 then ''是''
    else ''''end ) as IsRef
    ,Abstract
    from [liupeng]'
    ,@varExcelFullPath= 'E:\aa004.xls',@varSheetName= 'sheet',@varOrderBy='TopIdentitier,DocID'

    p_QueryToExcel @varQuerySQL= 'select top 102400
    DocID,
    MetaTypeID,
    MetaID,
    Title,
    Creator,
    [Year],
    Publisher,
    PublishDate,
    Price,
    ISBN,
    IssueDate,
    IsScan,
    Status,
    InsertedTime,substring(Abstract,1,255) as 摘要 from ast_document'
    ,@varExcelFullPath= 'E:\aa2.xls',@varSheetName= 'sheet',@varOrderBy='MetaID,Title'

    --Excel 12:[Sheet1$]则,会报错“书签无效”,应使用'select * from [Sheet1$]'
    insert into OPENROWSET('Microsoft.ACE.OLEDB.12.0',
    'Excel 12.0;Database=D:\test.xlsx;',
    'select * from [Sheet1$]') select top 10 DocID from Test.dbo.ast_document

    --在Excel 12中一个sheet中加入10万条记录比在多个Sheet中加入10万条记录要满很多
    --因此不用Excel 12存
    SELECT *
    FROM OPENDATASOURCE( 'Microsoft.Jet.OLEDB.4.0',
    'Data Source=F:\aa.xls; Extended properties="Excel 8.0;HDR=YES"')...sheet$

    */

    ALTER proc [dbo].[p_QueryToExcel]
    @varQuerySQL varchar(8000), --@varQuerySQL:查询语句,各列必须有名称,没有的需要别名,由于
    --如果查询语句中使用了order by,请加上top 100 percent
    --对是否包含where分类限制不做要求
    @varExcelFullPath nvarchar(4000), --@varExcelFullPath:生成Excel的完整路径
    @varSheetName varchar(512) = 'sheet',
    @varOrderBy varchar(512) = '类目', --必须是@varQuerySQl中的列名
    @varArrayHiddenCols varchar(1024) = 'TopIdentitier,DocID'
    as
    begin
    --声明和初始化变量

    declare @varSheetName_pre varchar(1024)
    declare @intOneSheetMaxNumber int
    declare @intRecCount int
    declare @sinSheetNumber smallint
    declare @sinCircle int
    declare @varTempSQL varchar(8000)

    set @intOneSheetMaxNumber = 50000
    set @sinSheetNumber = 1
    set @varExcelFullPath = convert(varchar(8000),ltrim(rtrim(@varExcelFullPath)))
    set @varQuerySQL = lower(ltrim(rtrim(@varQuerySQL)))
    set @sinCircle = 0
    set @varSheetName_pre = @varSheetName
    set @varOrderBy = ltrim(rtrim(@varOrderBy))
    set @varArrayHiddenCols = lower(ltrim(rtrim(@varArrayHiddenCols)))
    --select top 1 1 from ast_document where metaid not in ('CategoryTypeID','DocID')
    set @varArrayHiddenCols = replace(@varArrayHiddenCols,',',',') --CategoryTypeID,DocID
    print @varArrayHiddenCols
    -- set @varOrderByWithNoAliasTable = ltrim(rtrim(@varOrderByWithNoAliasTable))
    -- --@varQuerySQL的别名这里取AAA
    -- if @varOrderByWithNoAliasTable is null or @varOrderByWithNoAliasTable = ''
    -- set @varOrderBy = 'Order by AAA.CategoryTypeid, AAA.HiberarchyCode'
    -- else
    -- set @varOrderBy = 'AAA.' + replace(@varOrderByWithNoAliasTable,',' ,',AAA.' )

    /*=================================检测参数有效性====================*/
    ----判断@varExcelFullPath
    if (@varExcelFullPath is null) or (@varExcelFullPath='')
    begin
    RAISERROR ('Excel文件路径不能为空。',1,1)
    return 50001
    end

    ----判断@varQuerySQL
    if (@varQuerySQL is null) or (@varQuerySQL = '')
    begin
    RAISERROR ('查询语句不能为空。',1,2)
    return 50001
    end

    ----判断@varQuerySQL 'SQL语句'
    ----假设用户没有恶意调用
    set @varTempSQL = @varQuerySQL
    if left(@varTempSQL,1) = '('
    begin
    RAISERROR ('不能将整个SQL语句用括号包起来。',2,16)
    return 50002
    end

    if charindex('select ',@varTempSQL,1) = 0
    begin
    RAISERROR ('Error 缺少select语句。',2,16)
    return 50002
    end

    if charindex(' aaa',@varTempSQL,1) > 0 or charindex(' bbb',@varTempSQL,1) > 0 or charindex(' myrownumber',@varTempSQL,1) > 0
    begin
    RAISERROR ('请使用AAA、BBB、MyRowNumber以外的别名。',2,16)
    return 50002
    end

    if left(@varTempSQL,1) = '('
    begin
    RAISERROR ('不能将整个SQL语句用括号包起来。',2,16)
    return 50002
    end
    --针对'
    --set @varQuerySQL = replace(@varQuerySQL,char(39),char(39)+char(39))
    /*
    if charindex(char(39),@varTempSQL,1) > 0
    begin
    --RAISERROR ('Error 传输的SQL语句不能包含英文撇,请使用''代替。',3,17)
    --return 50002
    end
    */

    if @varOrderBy is null or @varOrderBy =''
    begin
    RAISERROR ('排序不能为空。',1,5)
    return 50001
    end
    else
    begin
    set @varOrderBy = 'BBB.' + replace(@varOrderBy,',',',BBB.')
    end
    print @varOrderBy

    --exec ('select 1 from (select * from ast_document where docid < 0) as A')
    --select 1以便得到count记录数,保证@varQuerySQL不包含AAA别名
    set @varTempSQL = 'select 1 from (' + @varQuerySQL + ') as AAA'
    exec (@varTempSQL)

    --@@rowcount在下一个begin...end之后就成为0
    set @intRecCount = @@rowcount
    if @intRecCount = 0
    begin
    RAISERROR ('查询记录集为空。',1,5)
    return 50001
    end
    print @intRecCount


    declare @varTopCategoryCode varchar(256)
    declare @varTopCategoryName varchar(512)
    declare @err int, @src varchar(255), @desc varchar(255), @out int --Error跟踪
    declare @obj int, @constr varchar(1000), @fdlist varchar(8000), @fdlist_AAA varchar(8000)
    declare @tbname sysname

    --检查Excel文件是否已经存在
    create table #tb(a bit,b bit,c bit)
    set @varExcelFullPath = ltrim(rtrim(@varExcelFullPath))

    insert into #tb
    exec master..xp_fileexist @varExcelFullPath
    print 'xp_fileexist'+@varExcelFullPath
    --select * from #tb
    /*
    xp_fileexist 返回的三个列, 分别代表

    文件已存在 文件是目录 父目录已存在
    ----- ----- ------
    0 0 1
    */

    /*
    declare @saveas varchar(2048),@sheet int

    set @saveas = 'ActiveWorkbook.SaveAs("'+@varExcelFullPath+'")'

    exec @err = sp_oacreate 'excel.application' ,@obj output
    if @err <> 0 goto lberr

    exec @err = sp_oamethod @obj ,'workbooks.add' ,@sheet output
    if @err <> 0 goto lberr

    exec @err = sp_oamethod @obj ,@saveas
    if @err <> 0 goto lberr

    --exec @err = sp_oamethod @obj ,'ActiveWorkbook.Save'
    if @err <> 0 goto lberr

    exec @err = sp_oamethod @obj ,'Workbooks.Close'
    if @err <> 0 goto lberr

    exec @err = sp_oamethod @obj ,'quit'
    exec @err = sp_oadestroy @obj

    return
    */

    --数据库创建语句
    set @varTempSQL = @varExcelFullPath
    if exists(select 1 from #tb where a=1)
    begin
    --set @constr= 'DRIVER={Microsoft Excel Driver (*.xls)};DSN= '''';READONLY=FALSE '
    -- + ';CREATE_DB= "'+@sql+ '";DBQ='+@sql
    RAISERROR ('暂不支持对已经存在的Excel,做导出操作。',1,5)
    return 50001
    end
    else
    set @constr= 'Provider=Microsoft.Jet.OLEDB.4.0;Data Source='+@varExcelFullPath+ ';Extended Properties="Excel 8.0;HDR=YES"'
    --set @constr= 'Provider=Microsoft.ACE.OLEDB.12.0;Data Source='+@varExcelFullPath+ ';Extended Properties="Excel 12.0;HDR=YES"'


    --连接数据库
    EXEC @err=sp_OACreate 'ADODB.Connection', @obj OUT
    print '连接数据库1'+convert(varchar(50),@obj)
    if @err <> 0 goto lberr

    EXEC @err=sp_OASetProperty @obj,'ConnectionString', @constr
    if @err <> 0 goto lberr

    exec @err=sp_oamethod @obj, 'Open'
    print '连接数据库2'+@constr
    if @err <> 0 goto lberr

    print '创建临时表1'

    --创建相同表结构的临时表
    set @tbname= '##tmp_'+convert(varchar(38),newid())
    set @varTempSQL= 'select top 1 AAA.* into ['+@tbname+ '] from ('+@varQuerySQL+ ') AAA'
    print '创建临时表2'+@varTempSQL
    exec(@varTempSQL)

    set @varTempSQL = ''
    set @fdlist = ''
    set @fdlist_AAA = ''
    select @fdlist=@fdlist+ ',['+a.name+']'
    ,@varTempSQL=@varTempSQL+',['+a.name+'] '
    +case
    when b.name like '%char'
    then case when a.length> 255 then 'text(255)'
    else 'text('+cast(a.length as varchar)+')' end
    when b.name like '%int' or b.name='bit' then 'int'
    when b.name like '%datetime' then 'datetime'
    when b.name like '%money' then 'money'
    when b.name like '%text' then 'memo'
    else b.name end
    FROM tempdb..syscolumns a
    left join tempdb..systypes b
    on a.xtype=b.xusertype
    where b.name not in('image','uniqueidentifier','sql_variant','varbinary','binary','timestamp')
    and a.id=(select id from tempdb..sysobjects where name=@tbname)
    and charindex(a.name, @varArrayHiddenCols)=0

    select @fdlist_AAA=@fdlist_AAA+ ',AAA.['+a.name+']'
    FROM tempdb..syscolumns a
    left join tempdb..systypes b
    on a.xtype=b.xusertype
    where b.name not in('image','uniqueidentifier','sql_variant','varbinary','binary','timestamp')
    and a.id=(select id from tempdb..sysobjects where name=@tbname)
    and charindex(a.name, @varArrayHiddenCols)=0

    print @fdlist + ' ' +@fdlist_AAA
    print'转换数据类型'

    /*=====================分页插入Excel的Sheet=======================*/
    --如果不按分类存放

    --获得记录总数@intRecCount,上面判断时已经获得
    ----设置Sheet名称
    ----判断@intRecCount与@intOneSheetMaxNumber大小,定义Sheet名称后
    ----分页插入各个Sheet

    --如果<=@intOneSheetMaxNumber
    if @intRecCount <= @intOneSheetMaxNumber
    begin
    set @varSheetName = @varSheetName_pre + '1'
    --直接创建Excel和导入数据
    set @varTempSQL= 'create table ['+@varSheetName + '] ('
    + substring(@varTempSQL,2,8000)+ ')'
    set @fdlist=substring(@fdlist,2,8000)
    set @fdlist_AAA=substring(@fdlist_AAA,2,8000)

    print '准备创建Table '+@varTempSQL
    exec @err=sp_oamethod @obj, 'Execute',@out out,@varTempSQL
    if @err <> 0 goto lberr

    --为导入数据
    set @varTempSQL= 'openrowset(''MICROSOFT.JET.OLEDB.4.0'',''Excel 8.0;HDR=Yes;database='+@varExcelFullPath+ ''',['+@varSheetName+ '$])'
    --set @varTempSQL= 'openrowset(''Microsoft.ACE.OLEDB.12.0'',''Excel 12.0;HDR=Yes;database='+@path+@fname+ ''',''select * from ['+@varSheetName+ '$]'')'
    print '导入数据:'+'insert into '+@varTempSQL+ '('+@fdlist+ ') select '+@fdlist_AAA+ ' from ('+@varQuerySQL+ ') as AAA'
    exec('insert into '+@varTempSQL+ '('+@fdlist+ ') select '+@fdlist_AAA+ ' from ('+@varQuerySQL+ ') as AAA')
    end
    --如果>@intOneSheetMaxNumber
    else
    begin
    set @sinSheetNumber = @intRecCount / @intOneSheetMaxNumber
    + (case (@intRecCount % @intOneSheetMaxNumber) when 0 then 0 else 1 end)

    set @fdlist=substring(@fdlist,2,8000)
    set @fdlist_AAA=substring(@fdlist_AAA,2,8000)

    while ( @sinCircle < @sinSheetNumber )
    begin
    set @varSheetName = @varSheetName_pre + convert(varchar(50),@sinCircle+1)
    print '第 ' + convert(varchar(50),@sinCircle+1) + ' 个Sheet / 总共 ' + convert(varchar(50),@sinSheetNumber) + ' 个Sheet'
    --直接创建Excel和导入数据
    declare @varTempSQL2 varchar(8000)
    set @varTempSQL2 = ''
    select @varTempSQL2= 'create table ['+@varSheetName
    + '] ('+substring(@varTempSQL,2,8000)+ ')'


    print '准备创建Table ' + @varTempSQL2
    exec @err=sp_oamethod @obj, 'Execute',@out out,@varTempSQL2
    print 'create table :'+@varTempSQL
    if @err <> 0 goto lberr

    --为导入数据
    /*
    WITH OrderedTable AS
    (
    SELECT BBB.*,ROW_NUMBER() OVER (ORDER BY Docid) AS 'MyRowNumber'
    FROM (@varQuerySQL) as BBB
    )
    insert into openrowset() (@fdlist)
    SELECT @fdlist
    FROM OrderedTable
    WHERE MyRowNumber BETWEEN (@intOneSheetMaxNumber * @sinCircle) AND (@intOneSheetMaxNumber * (@sinCircle+1))
    */
    --set @varTempSQL= 'openrowset(''MICROSOFT.JET.OLEDB.4.0'',''Excel 8.0;HDR=Yes;database='+@varExcelFullPath+ ''',['+@varSheetName+ '$])'
    --set @varTempSQL= 'openrowset(''Microsoft.ACE.OLEDB.12.0'',''Excel 12.0;HDR=Yes;database='+@path+@fname+ ''',''select * from ['+@varSheetName+ '$]'')'

    set @varTempSQL2 = 'WITH OrderedTable AS
    (
    SELECT BBB.*,ROW_NUMBER() OVER (ORDER BY '+@varOrderBy +') AS ''MyRowNumber''
    FROM (' + @varQuerySQL + ') as BBB
    )
    insert into openrowset(''MICROSOFT.JET.OLEDB.4.0'',''Excel 8.0;HDR=Yes;database='+@varExcelFullPath+ ''',['+@varSheetName+ '$])'
    + ' select ' + @fdlist + ' FROM OrderedTable WHERE MyRowNumber BETWEEN ' + convert(varchar(50),@intOneSheetMaxNumber * @sinCircle+1) + ' AND ' + convert(varchar(50),@intOneSheetMaxNumber * (@sinCircle+1))

    print '导入数据:'+@varTempSQL2
    exec(@varTempSQL2)

    set @sinCircle = @sinCircle + 1
    end
    end


    --关闭和释放OA对象
    EXEC @err=sp_OAMethod @obj, 'Close'
    EXEC @err=sp_OAMethod @obj, 'Dispose'
    print 'sp_oadestroy'+convert(varchar(50),@obj)
    EXEC @err=sp_OADestroy @obj

    set @varTempSQL= 'drop table ['+@tbname+ ']'
    print 'drop table '+@varTempSQL
    exec(@varTempSQL)

    return
    lberr:
    exec sp_oageterrorinfo 0,@src out,@desc out
    lbexit:
    select cast(@err as varbinary(4)) as 错误号
    ,@src as 错误源,@desc as 错误描述
    select @varTempSQL,@constr,@fdlist

    end

  • 相关阅读:
    Solr环境配置
    SolrJ解析MoreLikeThis查询结果
    思维导图软件PersonalBrain 6.0.6.4破解版使用
    离散对数-详解
    转:pptp和l2tp的区别
    DiffieHellman Key Exchange (DH)源代码
    磁盘IOPS计算
    转:TCP/IP Network Performance Benchmarks and Tools
    转:弄清楚你的业务类型——OLTP or OLAP
    U8软件的端口
  • 原文地址:https://www.cnblogs.com/y0umer/p/3839295.html
Copyright © 2011-2022 走看看