使用存储过程将Excel工作表数据导入SQL表的技术咨询
实现方案:用存储过程导入Excel销量数据到SQL表
嘿,我来帮你搞定这个需求——把Excel里的月度销量数据导入到带唯一约束的SQL表中,全程用存储过程实现。下面是一步步的详细方案:
1. 先创建目标SQL表
首先得搭好目标表的架子,我们需要productname和month作为唯一组合,直接给这俩字段加个主键约束就能保证唯一性了:
CREATE TABLE ProductMonthlySales ( productname VARCHAR(100) NOT NULL, month DATE NOT NULL, sales INT NULL, CONSTRAINT PK_ProductMonthlySales PRIMARY KEY (productname, month) );
2. 编写核心存储过程
这个存储过程要干三件事:读取Excel数据、把宽表(每个月一列)转成窄表(每行一条月度记录)、插入到目标表(还得避免重复插入)。
提前注意两点:
- 确保SQL Server的服务账户有访问你Excel文件路径的权限(比如文件在
C:\Data\Sales.xlsx,得给服务账户读权限) - 如果是64位SQL Server,得装64位的Microsoft Access Database Engine(ACE驱动),不然会找不到Excel驱动
存储过程代码如下:
CREATE PROCEDURE ImportProductSalesFromExcel @ExcelFilePath NVARCHAR(255), @SheetName NVARCHAR(50) = 'Sheet1' -- 默认用Sheet1,你可以按需改 AS BEGIN SET NOCOUNT ON; -- 先建个临时表存Excel读出来的原始宽表数据 CREATE TABLE #TempSalesData ( Product VARCHAR(100), [Jul-17] INT, [Aug-17] INT, [Sep-17] INT, [Oct-17] INT, [Nov-17] INT, [Dec-17] INT, [Jan-18] INT, [Feb-18] INT, [Mar-18] INT, [Apr-18] INT, [May-18] INT, [Jun-18] INT ); -- 用OPENROWSET读取Excel数据到临时表 DECLARE @SQL NVARCHAR(MAX); SET @SQL = N' INSERT INTO #TempSalesData SELECT * FROM OPENROWSET( ''Microsoft.ACE.OLEDB.12.0'', ''Excel 12.0 Xml;HDR=YES;Database=' + @ExcelFilePath + ''', ''SELECT * FROM [' + @SheetName + '$]'' ); '; EXEC sp_executesql @SQL; -- 把宽表转成窄表,插入到目标表 -- 用UNPIVOT来把月份列转成行记录 INSERT INTO ProductMonthlySales (productname, month, sales) SELECT Product AS productname, -- 把Jul-17这种格式转成标准日期(比如2017-07-01) CAST('01-' + MonthCol AS DATE) AS month, SalesValue AS sales FROM #TempSalesData UNPIVOT ( SalesValue FOR MonthCol IN ( [Jul-17], [Aug-17], [Sep-17], [Oct-17], [Nov-17], [Dec-17], [Jan-18], [Feb-18], [Mar-18], [Apr-18], [May-18], [Jun-18] ) ) AS UnpivotData -- 过滤掉空销量的记录(不需要的话可以删掉这个条件) WHERE SalesValue IS NOT NULL -- 跳过已经存在的product+month组合,避免主键冲突 AND NOT EXISTS ( SELECT 1 FROM ProductMonthlySales WHERE productname = UnpivotData.Product AND month = CAST('01-' + UnpivotData.MonthCol AS DATE) ); -- 清理临时表 DROP TABLE #TempSalesData; PRINT '数据导入搞定啦!'; END;
3. 调用存储过程的方式
比如你的Excel文件在C:\Sales\MonthlySalesData.xlsx,工作表名叫SalesRecords,直接这么调用就行:
EXEC ImportProductSalesFromExcel @ExcelFilePath = N'C:\Sales\MonthlySalesData.xlsx', @SheetName = N'SalesRecords';
额外优化:支持更新已有记录
如果后续导入相同product+month组合时,你想更新销量而不是跳过,可以把上面的INSERT改成MERGE语句,替换掉原来的INSERT部分:
MERGE INTO ProductMonthlySales AS Target USING ( SELECT Product AS productname, CAST('01-' + MonthCol AS DATE) AS month, SalesValue AS sales FROM #TempSalesData UNPIVOT ( SalesValue FOR MonthCol IN ( [Jul-17], [Aug-17], [Sep-17], [Oct-17], [Nov-17], [Dec-17], [Jan-18], [Feb-18], [Mar-18], [Apr-18], [May-18], [Jun-18] ) ) AS UnpivotData WHERE SalesValue IS NOT NULL ) AS Source ON Target.productname = Source.productname AND Target.month = Source.month WHEN MATCHED THEN UPDATE SET Target.sales = Source.sales -- 已有记录就更新销量 WHEN NOT MATCHED THEN INSERT (productname, month, sales) VALUES (Source.productname, Source.month, Source.sales); -- 没有就插入新记录
小提示
- 如果你的Excel是旧的
.xls格式,把OPENROWSET里的Excel 12.0 Xml改成Excel 8.0就行。
内容的提问来源于stack exchange,提问作者samaposha




