如何将多工作表Excel数据导入SQL Server?含bcp与PowerShell场景
解决多工作表Excel导入SQL Server的问题(替代bcp方案)
首先得说清楚:bcp工具没法直接处理Excel文件——它是专门用来读写平面文本(比如CSV、TSV)或SQL原生格式的,根本解析不了Excel的工作表结构和二进制格式,所以你直接用bcp调用.xls文件肯定会失败。下面给你两个更实用的解决方案,分别适合用PowerShell自动化处理,或者直接在SQL Server里操作。
方案一:用PowerShell+ImportExcel模块(推荐自动化场景)
这个方法能轻松读取Excel的所有工作表,还能灵活实现「单表加category列」或「分表导入」的需求,而且能和你现有的下载脚本无缝整合。
步骤1:先安装所需模块
打开PowerShell(管理员权限),执行下面的命令安装模块(如果已经装过就跳过):
# 安装读取Excel的模块 Install-Module -Name ImportExcel -Scope CurrentUser -Force # 安装SQL Server操作模块 Install-Module -Name SqlServer -Scope CurrentUser -Force
步骤2:整合脚本实现导入
场景1:导入到同一表,新增category列存储工作表名
把下面的代码加到你现有的下载脚本后面:
# 你的下载脚本(保留原内容) $webclient = New-Object System.Net.webclient $source = "http://www.dtcc.com/~/media/Files/Downloads/client-center/NSCC/NSCC-MPID-Directory.xls" $destination = "C:\LSC\NSCC_MPID\NSCC-MPID-Directory.xls" $webclient.DownloadFile($source, $destination) # ------------------- 新增导入逻辑 ------------------- # 配置SQL Server参数 $sqlInstance = "database1" $dbName = "SIAC" $targetTable = "dbo.NSCC_MPID" # 获取Excel里的所有工作表 $excelSheets = Get-ExcelSheetInfo -Path $destination # 循环处理每个工作表 foreach ($sheet in $excelSheets) { $sheetName = $sheet.Name Write-Host "正在处理工作表:$sheetName" # 读取当前工作表的数据 $sheetData = Import-Excel -Path $destination -WorksheetName $sheetName # 新增category列,值为当前工作表名称 $sheetData | Add-Member -MemberType NoteProperty -Name "category" -Value $sheetName -Force # 导入到SQL Server(如果表不存在,会自动创建;如果已存在,会追加数据) Write-SqlTableData -ServerInstance $sqlInstance -DatabaseName $dbName -TableName $targetTable -InputData $sheetData -Force }
场景2:每个工作表导入到单独的表
只需修改循环部分的逻辑,让每个工作表对应一个独立的SQL表(比如工作表OTC对应表NSCC_MPID_OTC):
# 循环处理每个工作表 foreach ($sheet in $excelSheets) { $sheetName = $sheet.Name # 把工作表名转成合法的SQL表名(替换空格/特殊字符) $targetTableForSheet = "dbo.NSCC_MPID_$($sheetName.Replace(' ', '_'))" Write-Host "正在处理工作表:$sheetName -> 导入到表:$targetTableForSheet" $sheetData = Import-Excel -Path $destination -WorksheetName $sheetName Write-SqlTableData -ServerInstance $sqlInstance -DatabaseName $dbName -TableName $targetTableForSheet -InputData $sheetData -Force }
方案二:用SQL Server的OPENROWSET直接读取Excel
如果习惯在SQL里操作,可以用这个方法直接读取Excel工作表,然后插入到目标表。需要先在SQL Server服务器上安装Microsoft Access Database Engine(ACE驱动)(注意和SQL Server的位数匹配:64位SQL要装64位ACE驱动)。
步骤1:启用Ad Hoc分布式查询(临时开启,用完可关闭)
sp_configure 'show advanced options', 1; RECONFIGURE; sp_configure 'Ad Hoc Distributed Queries', 1; RECONFIGURE; GO
步骤2:导入数据
场景1:导入到同一表,新增category列
假设你已经创建好目标表NSCC_MPID(包含Excel所有列和category列),执行下面的语句(每个工作表对应一条INSERT,替换工作表名即可):
-- 导入OTC工作表的数据,category值为'OTC' INSERT INTO SIAC.dbo.NSCC_MPID (列1, 列2, ..., category) SELECT 列1, 列2, ..., 'OTC' AS category FROM OPENROWSET('Microsoft.ACE.OLEDB.12.0', 'Excel 12.0;Database=C:\LSC\NSCC_MPID\NSCC-MPID-Directory.xls;HDR=YES', 'SELECT * FROM [OTC$]'); -- 导入其他工作表,比如Sheet2 INSERT INTO SIAC.dbo.NSCC_MPID (列1, 列2, ..., category) SELECT 列1, 列2, ..., 'Sheet2' AS category FROM OPENROWSET('Microsoft.ACE.OLEDB.12.0', 'Excel 12.0;Database=C:\LSC\NSCC_MPID\NSCC-MPID-Directory.xls;HDR=YES', 'SELECT * FROM [Sheet2$]');
场景2:动态处理所有工作表(无需手动写每个工作表的语句)
用游标自动遍历所有工作表并导入:
DECLARE @excelPath NVARCHAR(500) = 'C:\LSC\NSCC_MPID\NSCC-MPID-Directory.xls'; DECLARE @sheetName NVARCHAR(100); DECLARE @sql NVARCHAR(MAX); -- 临时表存储所有工作表名 CREATE TABLE #Sheets (SheetName NVARCHAR(100)); INSERT INTO #Sheets SELECT TABLE_NAME FROM OPENROWSET('Microsoft.ACE.OLEDB.12.0', 'Excel 12.0;Database=' + @excelPath + ';HDR=YES', 'SELECT TABLE_NAME FROM [Excel 12.0;HDR=YES].INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE=''TABLE'''); -- 遍历每个工作表 DECLARE sheetCursor CURSOR FOR SELECT SheetName FROM #Sheets; OPEN sheetCursor; FETCH NEXT FROM sheetCursor INTO @sheetName; WHILE @@FETCH_STATUS = 0 BEGIN -- 构建导入语句,自动创建对应表(或追加数据) SET @sql = N' SELECT * INTO SIAC.dbo.NSCC_MPID_' + REPLACE(REPLACE(@sheetName, '$', ''), ' ', '_') + ' FROM OPENROWSET(''Microsoft.ACE.OLEDB.12.0'', ''Excel 12.0;Database=' + @excelPath + ';HDR=YES'', ''SELECT * FROM [' + @sheetName + ']''); '; EXEC sp_executesql @sql; FETCH NEXT FROM sheetCursor INTO @sheetName; END CLOSE sheetCursor; DEALLOCATE sheetCursor; DROP TABLE #Sheets;
注意事项
- PowerShell方案需要确保执行策略允许运行脚本:
Set-ExecutionPolicy RemoteSigned -Scope CurrentUser - ACE驱动的位数必须和SQL Server一致,否则会报错「找不到数据源」
- 如果预先创建SQL表,要确保表结构和Excel列的类型、顺序匹配,避免导入失败
内容的提问来源于stack exchange,提问作者Rachel




