https://www.cnblogs.com/downmoon/archive/2012/05/04/2482995.html

 

SQL Server 2008中SQL应用系列及BI学习笔记系列--目录索引

前几天在项目中遇到一个问题,需要从SQL Server导出表到Excel,但需要带列名。晚上尝试了几种方法,并作个小结。

假定表如下:

USE testDb2
GO
IF NOT OBJECT_ID('Demo_A') IS NULL
DROP TABLE [Demo_A] /****** Object: Table [dbo].[Demo_A] downmoon:3w@live.cn ******/
CREATE TABLE [dbo].[Demo_A](
[ID] int not null,
[Name] [Nvarchar](20) NOT NULL
)
GO
INSERT [dbo].[Demo_A]
SELECT 1,'郭靖'
union ALL SELECT 2,'胡一刀'
union ALL SELECT 3,'令狐冲'
GO

如果通常的思路,我们可以用BCP,命令如下:

-- To allow advanced options to be changed.
EXEC sp_configure 'show advanced options', 1
GO
-- To update the currently configured value for advanced options.
RECONFIGURE
GO
-- To enable the feature.
EXEC sp_configure 'xp_cmdshell', 1
GO
-- To update the currently configured value for this feature.
RECONFIGURE
GO EXEC master..xp_cmdshell 'bcp Testdb2.dbo.Demo_A out c:\Temp.xls -c -q -S"ap4\Net2012" -U"sa" -P"sA"'

这样得到的xls文件中,Sheet是不带列名的。但可以改进一下,得到如下命令(参考:http://social.msdn.microsoft.com/forums/en-US/sqlgetstarted/thread/812b8eec-5b77-42a2-bd23-965558ece5b9/):

 

方法一:使用BCP

为了方便,我创建了一个存储过程:

/****** SQL Export to xls ***************/
/* Example */
/*CPP_Export_To_Excel_With_Header 'Testdb2','Demo_A','C:\TestExxelWithHeader.xls'*/
/* 2012.5.4 BY tony,邀月, 3w@live.cn */
---- CPP_Export_To_Excel_With_Header 'Testdb2','Demo_A','C:\TestExcelWithHeader.xls' Create Procedure CPP_Export_To_Excel_With_Header
(
@db_name varchar(255),
@table_name varchar(255),
@file_path varchar(255)
)
as ----Generate column names as a recordset
declare @columns varchar(8000), @sql varchar(8000)
declare @HeadersOnlyFile varchar(255),@TableDataWithoutHeaders varchar(255)
set @HeadersOnlyFile=replace(cast(newid() as VARCHAR(40)),'-','')+'1.xls' set @TableDataWithoutHeaders=replace(cast(newid() as VARCHAR(40)),'-','')+'2.xls'
select
@columns=coalesce(@columns+',','')+column_name+' as '+column_name
from
information_schema.columns
where
table_name=@table_name
select @columns=''''''+replace(replace(@columns,' as ',''''' as '),',',',''''')
print @columns
----Generate column names file
set @sql='exec master..xp_cmdshell ''bcp " select * from (select '+@columns+') as t" queryout "'+@HeadersOnlyFile+'" -c'''
print @sql
exec(@sql) ----Create a dummy file to have actual data
set @sql='exec master..xp_cmdshell ''bcp "'+@db_name+'.dbo.'+@table_name+'" out "'+@TableDataWithoutHeaders+'" -c -t -T'''
print @sql
exec(@sql) --Merge File into One Final Format
set @sql='exec master..xp_cmdshell ''copy /b '+@HeadersOnlyFile+'+'+@TableDataWithoutHeaders+' '+@file_path+''''
print @sql
exec(@sql) --Delete temp File
set @sql='exec master..xp_cmdshell ''del '+@HeadersOnlyFile+''''
exec(@sql)
set @sql='exec master..xp_cmdshell ''del '+@TableDataWithoutHeaders+''''
exec(@sql)

调用方法:

CPP_Export_To_Excel_With_Header 'Testdb2','Demo_A','C:\TestExcelWithHeader.xls'

另外有类似的处理方法:(看这里:http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=49926),其主要思路如下:

 

方法二:

create procedure proc_generate_excel_with_columns
(
@db_name varchar(100),
@table_name varchar(100),
@file_name varchar(100)
)
as --Generate column names as a recordset
declare @columns varchar(8000), @sql varchar(8000), @data_file varchar(100)
select
@columns=coalesce(@columns+',','')+column_name+' as '+column_name
from
information_schema.columns
where
table_name=@table_name
select @columns=''''''+replace(replace(@columns,' as ',''''' as '),',',',''''') --Create a dummy file to have actual data
select @data_file=substring(@file_name,1,len(@file_name)-charindex('\',reverse(@file_name)))+'\data_file.xls' --Generate column names in the passed EXCEL file
set @sql='exec master..xp_cmdshell ''bcp " select * from (select '+@columns+') as t" queryout "'+@file_name+'" -c'''
exec(@sql) --Generate data in the dummy file
set @sql='exec master..xp_cmdshell ''bcp "select * from '+@db_name+'..'+@table_name+'" queryout "'+@data_file+'" -c'''
exec(@sql) --Copy dummy file to passed EXCEL file
set @sql= 'exec master..xp_cmdshell ''type '+@data_file+' >> "'+@file_name+'"'''
exec(@sql) --Delete dummy file
set @sql= 'exec master..xp_cmdshell ''del '+@data_file+''''
exec(@sql)

调用示例:

EXEC proc_generate_excel_with_columns 'your dbname', 'your table name','your file path'

如果,你的环境是SQL Server 2005,那么可以有:

 

方法三,使用sp_makewebtask,仅适用于SQL Server 2005

0)表T1结构
a int
b int
x char 1)开启Web Assistant Procedures exec sp_configure 'show advanced options', 1
RECONFIGURE
exec sp_configure 'Web Assistant Procedures', 1
RECONFIGURE 2)执行如下语句 EXEC sp_makewebtask
@outputfile = 'd:\testing.xls',
@query = 'Select TOP 10 * from shenliang1985..T1',
@colheaders =1,
@FixedFont=0,@lastupdated=0,@resultstitle='Querying details' 3)查看生成的EXCEl的 Querying details Last updated: 2010-03-03 01:02:59.263 a b x
0 0 0
2 5 1
4 10 2
6 15 3
8 20 4
10 25 5
12 30 6
14 35 7
16 40 8
18 45 9

可惜SQL Server 2008以后sp_makewebtask 这个存储过程取消了,后续版本也不再启用。
方法一和方法二其实生成的文件都不上真正的Excel文件,虽然后缀名为xls,为此,找到邹建写的一个存储过程。

 

方法四,使用OpenRowSet:

/*--数据导出EXCEL

导出查询中的数据到Excel,包含字段名,文件为真正的Excel文件
如果文件不存在,将自动创建文件
如果表不存在,将自动创建表
基于通用性考虑,仅支持导出标准数据类型 --邹建 2003.10(引用请保留此信息)--*/ /*--调用示例 p_exporttb @sqlstr='select * from 地区资料'
,@path='c:\',@fname='aa.xls',@sheetname='地区资料'
--*/
create proc p_exporttb
@sqlstr varchar(8000),--查询语句,如果查询语句中使用了order by ,请加上top 100 percent
@path nvarchar(1000),--文件存放目录
@fname nvarchar(250),--文件名
@sheetname varchar(250)=''--要创建的工作表名,默认为文件名
as
declare @err int,@src nvarchar(255),@desc nvarchar(255),@out int
declare @obj int,@constr nvarchar(1000),@sql varchar(8000),@fdlist varchar(8000) --参数检测
if isnull(@fname,'')=''set @fname='temp2012.xls'
if isnull(@sheetname,'')='' set @sheetname=replace(@fname,'.','#') --检查文件是否已经存在
if right(@path,1)<>'\' set @path=@path+'\'
create table #tb(a bit,b bit,c bit)
set @sql=@path+@fname
insert into #tb exec master..xp_fileexist @sql --数据库创建语句
set @sql=@path+@fname
if exists(select 1 from #tb where a=1)
set @constr='DRIVER={Microsoft Excel Driver (*.xls)};DSN='''';READONLY=FALSE'
+';CREATE_DB="'+@sql+'";DBQ='+@sql
else
set @constr='Provider=Microsoft.Jet.OLEDB.4.0;Extended Properties="Excel 8.0;HDR=YES'
+';DATABASE='+@sql+'"' --连接数据库
exec @err=sp_oacreate 'adodb.connection',@obj out
if @err<>0 goto lberr exec @err=sp_oamethod @obj,'open',null,@constr
if @err<>0 goto lberr --创建表的SQL
declare @tbname sysname
set @tbname='##tmp_'+convert(varchar(38),newid())
set @sql='select * into ['+@tbname+'] from('+@sqlstr+') a'
exec(@sql) select @sql='',@fdlist=''
select @fdlist=@fdlist+',['+a.name+']'
,@sql=@sql+',['+a.name+'] '
+case
when b.name like '%char'
then case when a.length>255 then 'memo'
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) if @@rowcount=0 return select @sql='create table ['+@sheetname
+']('+substring(@sql,2,8000)+')'
,@fdlist=substring(@fdlist,2,8000) exec @err=sp_oamethod @obj,'execute',@out out,@sql
if @err<>0 goto lberr exec @err=sp_oadestroy @obj --导入数据
set @sql='openrowset(''MICROSOFT.JET.OLEDB.4.0'',''Excel 8.0;HDR=YES
;DATABASE='+@path+@fname+''',['+@sheetname+'$])' exec('insert into '+@sql+'('+@fdlist+') select '+@fdlist+' from ['+@tbname+']') set @sql='drop table ['+@tbname+']'
exec(@sql)
return lberr:
exec sp_oageterrorinfo 0,@src out,@desc out
lbexit:
select cast(@err as varbinary(4)) as 错误号
,@src as 错误源,@desc as 错误描述
select @sql,@constr,@fdlist
go

为了执行这个存储过程,你得先打开以下开关:

-- To allow advanced options to be changed.
EXEC sp_configure 'show advanced options', 1
GO
-- To allow advanced options to be changed.
EXEC sp_configure 'Ole Automation Procedures', 1
GO EXEC sp_configure 'Ad Hoc Distributed Queries', 1
GO -- To update the currently configured value for advanced options.
RECONFIGURE
GO

调用示例:

p_exporttb @sqlstr='select * from [Demo_A]'
,@path='c:\',@fname='Export2xls_ByProc.xls',@sheetname='员工名称'

结果确实是正宗的xls文件。

如果你是兼写程序的DBA,那么NPOI是你理想的选择,因为它是纯原生的不依赖于Office组件的开源第三方组件,它提供了一个“CreateExportDataTableSheetAndHeaderRow”方法可以让你方便的生成纯正的Excel,遗憾的是,目前好像只支持到Excel 2003。示例请看这儿(http://scottonwriting.net/sowblog/archive/2011/06/08/export-an-ado-net-datatable-to-excel-using-npoi.aspx),该组件的源码:http://npoi.codeplex.com/

 

方法五:

protected Sheet CreateExportDataTableSheetAndHeaderRow(DataTable exportData, string sheetName, CellStyle headerRowStyle)
{
var sheet = this.Workbook.CreateSheet(EscapeSheetName(sheetName)); // Create the header row
var row = sheet.CreateRow(0); for (var colIndex = 0; colIndex < exportData.Columns.Count; colIndex++)
{
var cell = row.CreateCell(colIndex);
cell.SetCellValue(exportData.Columns[colIndex].ColumnName); if (headerRowStyle != null)
cell.CellStyle = headerRowStyle;
} return sheet;
}

当然,如果你觉得以上方法门槛有点高,那么SSIS可能是你的首选,它的优势在于简单直观,并且可以导出为Excel2007格式。

只要在导出时选择第一行包含列名,即可。

 

方法六,使用SSIS

因为有人觉得界面过于繁琐,于是仿照导出向导的思路写了一个批处理,你可以修改为自己适合的内容:

 

方法七:(http://social.msdn.microsoft.com/forums/en-US/sqlgetstarted/thread/812b8eec-5b77-42a2-bd23-965558ece5b9/)

@ECHO OFF
REM -------------------------------------------------------------------------------
REM Generic script for exporting data to file from SQL Server using a SQL query.
REM The resulting file will be tab separated with newline as the row delimiter.
REM A log file is generated and kept in case of an error or when in debug mode.
REM See command syntax for details.
REM
REM History:
REM 20120327 Lars Rönnbäck CREATED
REM -------------------------------------------------------------------------------
:constants
SET myCodePage=ACP
:variables
SET theQuery=%~1
SET theFile=%~2
SET theServer=%~3
SET theDebug=%~4
SET /a aRandomNumber=%random%%%1000
FOR /F "usebackq tokens=1-7* delims=.:/,- " %%a IN (`ECHO %DATE%_%TIME%`) DO (SET myStartTime=%%a%%b%%c%%d%%e%%f%%g)
SET myColumnQuery="select top 0 * into [#columns_%myStartTime%_%aRandomNumber%] from (%theQuery%) q; select stuff((select char(9) + c.name from tempdb.sys.columns c where c.object_id = t.object_id order by c.column_id for XML path(''), type).value('.', 'varchar(max)'), 1,1,'') AS Header from tempdb.sys.tables t where t.name like '#columns_%myStartTime%_%aRandomNumber%%%'"
SET myHeaderFile=%theFile%.%aRandomNumber%.header
SET myDataFile=%theFile%.%aRandomNumber%.data
SET myLogFile=%theFile%.%myStartTime%_%aRandomNumber%.log
:checks
IF "%theQuery%"=="" (
GOTO syntax
)
IF "%theFile%"=="" (
GOTO syntax
)
IF "%theServer%"=="" (
SET theServer=%COMPUTERNAME%
)
:information
ECHO Start Time: %myStartTime% >> "%myLogFile%" 2>&1
ECHO Random Number: %aRandomNumber% >> "%myLogFile%" 2>&1
ECHO File: %theFile% >> "%myLogFile%" 2>&1
ECHO Server Name: %theServer% >> "%myLogFile%" 2>&1
ECHO Query: >> "%myLogFile%" 2>&1
ECHO. >> "%myLogFile%" 2>&1
ECHO %theQuery% >> "%myLogFile%" 2>&1
:export
BCP %myColumnQuery% queryout "%myHeaderFile%" -T -S "%theServer%" -a 65535 -c -C %myCodePage% -q >> "%myLogFile%" 2>&1
IF ERRORLEVEL 1 GOTO error
BCP "%theQuery%" queryout "%myDataFile%" -T -S "%theServer%" -a 65535 -c -C %myCodePage% -q >> "%myLogFile%" 2>&1
IF ERRORLEVEL 1 GOTO error
ECHO. >> "%myLogFile%" 2>&1
ECHO Merging files... >> "%myLogFile%" 2>&1
ECHO. >> "%myLogFile%" 2>&1
COPY /A "%myHeaderFile%" + "%myDataFile%" "%theFile%" /B /Y >> "%myLogFile%" 2>&1
IF ERRORLEVEL 1 GOTO error
:cleanup
DEL "%myHeaderFile%" >NUL 2>&1
IF ERRORLEVEL 1 GOTO error
DEL "%myDataFile%" >NUL 2>&1
IF ERRORLEVEL 1 GOTO error
IF /I NOT [%theDebug%]==[Y] (
DEL "%myLogFile%"
)
IF ERRORLEVEL 1 GOTO error
GOTO end
:error
ECHO
ECHO ERROR: An export error has occured!
IF NOT [%myLogFile: =%]==[] (
ECHO Details can be found in:
ECHO %myLogFile%
)
ECHO
EXIT /B 1
:syntax
ECHO.
ECHO SYNTAX: %0 "sql query" "output file" [server] [Y]
ECHO -------------------------------------------------------------------------------
ECHO You must specify an SQL query and an output file name in which the results of
ECHO the query will be stored. Specifying a server is optional and defaults to the
ECHO server you are executing on. If a fourth argument is given as Y a log file of
ECHO the command outputs will be saved in the same folder as the output file.
ECHO -------------------------------------------------------------------------------
:end
REM This is the end.

小结:

1、导出带有列名的Excel,可以用BCP,语句最少,但导出的不是真正的Excel文件;

2、使用OpenRowset,可以导出真正的Excel;

3、使用NPOI,可以最大化地满足编程人员的需求,另外也可在导出时再做适当的逻辑处理,另外也不需要xp_cmdshell等额外的权限;

4、最简单的是使用SSIS的导出向导,界面直观,可以直接导出为Excel 2003/2007格式。

SQL Server带列名导出到Excel(Export to CSV with headers)的几个思路的更多相关文章

  1. sql server 表结构 导出 到excel

    SELECT 表名 then d.name else '' end, 表说明 then isnull(f.value,'') else '' end, -- 字段序号 = a.colorder, 字段 ...

  2. 从SQL Server中导入/导出Excel的基本方法(转)

    从sql server中导入/导出 excel 的基本方法 /*=========== 导入/导出 excel 的基本方法 ===========*/ 从excel文档中,导入数据到sql数据库中,很 ...

  3. 不同版本的SQL Server之间数据导出导入的方法及性能比较

    原文:不同版本的SQL Server之间数据导出导入的方法及性能比较 工作中有段时间常常涉及到不同版本的数据库间导出导入数据的问题,索性整理一下,并简单比较下性能,有所遗漏的方法也欢迎讨论.补充. 0 ...

  4. 在SQL Server中将数据导出为XML和Json

        有时候需要一次性将SQL Server中的数据导出给其他部门的也许进行关联或分析,这种需求对于SSIS来说当然是非常简单,但很多时候仅仅需要一次性导出这些数据而建立一个SSIS包就显得小题大做 ...

  5. SQL Server服务器上需要导入Excel数据的必要条件

    SQL Server服务器上需要导入Excel数据,必须安装2007 Office system 驱动程序:数据连接组件,或者Access2010的数据库引擎可再发行程序包,这样就不必在服务器上装Ex ...

  6. SQL Server 2008 R2导出数据脚本的方法

    以前看到有些朋友说必须SQL Server 2008才能导出包含数据的脚本,后来仔细研究发现其实SQL Server 2008 R2也是可以的,只需在导出的时候在高级中设置一下即可. 1.首先在数据库 ...

  7. Sql Server 带参数的存储过程执行方法

    Sql Server 带参数的存储过程执行方法 Visual C# 动态操作 SQL Server 数据库实例教程(4):带参数的存储过程执行方法 上一篇文章介绍了带参数的SQL语句执行方法和不带参数 ...

  8. sql点滴38—SQL Server 2008和SQL Server 2008 R2导出数据的选项略有不同

    原文:sql点滴38—SQL Server 2008和SQL Server 2008 R2导出数据的选项略有不同 说明: 以前要将一个表中的数据导出为脚本,只有用存储过程.现在在SQL Server ...

  9. 连接到 PostgreSQL 数据源(SQL Server 导入和导出向导)

    本主题向你介绍如何从 SQL Server 导入和导出向导的“选择数据源”页或“选择目标”页连接到 PostgreSQL 数据源. 重要 连接到 PostgreSQL 数据库的详细需求和先决条件不在此 ...

随机推荐

  1. The Number of Inversions

    For a given sequence A={a0,a1,...an−1}A={a0,a1,...an−1}, the number of pairs (i,j)(i,j) where ai> ...

  2. 创建spring boot 项目

    1.新建Spring Starter Project(需要连接外网) 2.选择web 3.点击完成,生成maven项目 pom文件默认有一些依赖,但是有一个地方报错,<parent>节点报 ...

  3. C 库函数 - strcpy()

    描述 C 库函数 char *strcpy(char *dest, const char *src) 把 src 所指向的字符串复制到 dest. 需要注意的是如果目标数组 dest 不够大,而源字符 ...

  4. 清理 /dev/vda1 系统磁盘

    df-h检查一台服务器磁盘使用空间,发现磁盘已经使用了100% 思路是: 1.cd /usr 2.du -sh * 看哪个目录占用空间大 3.重复前两步,根据实际情况删除或者移走 4.日志的话可以运行 ...

  5. SQL Server 检查和处理死锁问题

    SELECT spid, blocked, DB_NAME(sp.dbid) AS DBName, program_name, waitresource, lastwaittype, sp.login ...

  6. NVMe概况

    简介 NVMe是为满足企业和客户系统需求,利用基于PCIe的固态存储,而精心设计的一个优化的,高效的,可伸缩主机控制器接口.NVMe是为非易失性内存(NVM)技术从头开始全新构建的,目的在于超越硬盘驱 ...

  7. lamda表达式的两种写法

    public class Test{ public synchronized void test1(){ System.out.println("test1 start........... ...

  8. .net 文件接口的封装,写日志,创建文件log

    public class FileSupport { public static FileSupport Instance = new FileSupport(); public static str ...

  9. C++-随机数的产生

    一.随机数 以前学C语言的时候感觉随机数没啥用的,现在想想是自己无知啦,在帮人做一个项目的时候发现随机数还是相当有用的,我们可以利用随机数来生成大量的测试数据. 有两种方法可以让你的程序每次运行结果不 ...

  10. C#获取当前不同网卡对应的iP

    C#获取当前不同网卡对应的iP: public string GetLocalIP() { IPAddress localIp = null; try { IPAddress[] ipArray; i ...