You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何将多工作表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;

注意事项

  1. PowerShell方案需要确保执行策略允许运行脚本:Set-ExecutionPolicy RemoteSigned -Scope CurrentUser
  2. ACE驱动的位数必须和SQL Server一致,否则会报错「找不到数据源」
  3. 如果预先创建SQL表,要确保表结构和Excel列的类型、顺序匹配,避免导入失败

内容的提问来源于stack exchange,提问作者Rachel

火山引擎 最新活动