• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录

奋斗中...

曾经的程序员。ASP.NET/C#, JavaScript, PL/SQL, T-SQL; 工具: VS2003/2005, Oracle, SQLServer; 偶尔写点CSS, 批处理.
头脑中经常有新想法, 可惜没有去实现.
Never give up.
Never get into a fight with a pig. Both of you will get dirty. But the pig actually enjoys it.
  • 博客园
  • 联系
  • 订阅
  • 管理

公告

View Post

[DataBase][SQL Server]T-SQL动态语句导入Excel数据

缘由: 要导入一批数据, 为一年12个月的工资数据, Excel格式一致. 下面采用T-SQL动态语句来实现. 耗时比单独导入每个Excel表格数据要快很多. 拿我的这次导入的数据为例, 每个Excel导入需要大约20s以上, 而用动态语句将所有数据导入到全局临时表, 再处理, 只需要4s!

 

下面是一些我认为有用的T-SQL语句(其他无关语句已删除, 如果有错漏请指正, 因删除后无重新编译):

动态SQL语句
USE [TEST]
GO
/****** Object: StoredProcedure [dbo].[IMPORT_临工工资] Script Date: 01/18/2011 14:56:45 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[IMPORT_临工工资]
--注意: 用到的是全局临时表
--
为什么要用全局临时表? 因为采用动态语句的方式相当于两个连接? 所以后面exec动态语句后并不能得到临时表的数据
--
会提示临时表不存在. 至于在同个交易下可行不可行未测试
AS
BEGIN
-------------------------------------------------------------------
--
变量声明

--Excel路径可以作为参数传入
--
DECLARE @SHEET_NAME VARCHAR(256)
--
SET @SHEET_NAME

-------------------------------------------------------------------
--
判断全局临时表是否存在, 注意全局临时表命名不要太普通
IF EXISTS ( SELECT *
FROM tempdb.dbo.sysobjects
WHERE id = OBJECT_ID(N'TEMPDB..##TEMP_临工雇员_D2D119452A60497099FB24DF477EEB0A')
AND TYPE = 'U' )
BEGIN
TRUNCATE TABLE ##TEMP_临工雇员_D2D119452A60497099FB24DF477EEB0A
DROP TABLE ##TEMP_临工雇员_D2D119452A60497099FB24DF477EEB0A
END

DECLARE @s VARCHAR(MAX)
DECLARE @s1 VARCHAR(MAX)

DECLARE @I INT --循环变量
SET @I = 0

--循环拼SQL
WHILE @I < 12
BEGIN
SET @I = @I + 1
DECLARE @NOTE VARCHAR(255)
SET @NOTE = '2010年' + CAST(@I AS VARCHAR) + '月临工工资'

--注意: 单引号在拼SQL时需要特殊处理
SET @s1 = '
SELECT [2010年
' + CAST(@I AS VARCHAR) + '月临工工资] AS 代号 ,' + ''''
+ '2010-' + CAST(@I AS VARCHAR) + '-1' + '''' + ' AS 月份, '
+ '
F2 AS 姓名 ,
F3 AS 单位 ,
F17 AS 应发数 ,
' + '''' + @NOTE + '''' + ' AS 备注
FROM OPENDATASOURCE(
' + '''' + 'MICROSOFT.ACE.OLEDB.12.0' + ''''
+ ',' + '''' + 'Data Source=D:\2010年'
+ CAST(@I AS VARCHAR)
+ '月份临工工资.xls;Extended Properties=Excel 5.0' + ''''
+ ')...[汇总明细表$] A ' + '
'
IF ( @I > 1 )
SET @s = @s + ' UNION ' + @s1
ELSE
SET @s = @s1
END

SET @s = 'SELECT
月份 ,
代号 ,
姓名 ,
单位 ,
备注
INTO ##TEMP_临工雇员_D2D119452A60497099FB24DF477EEB0A FROM (
'
+ @s + '
) T
'

--PRINT是调试动态语句的有效方法
--PRINT ( @s )

--执行拼好的SQL, 使得数据导入到全局临时表
EXEC (@s)

/*
--注意1: 像下面这种直接执行的语句, OPENDATASOURCE第二个参数不能实用变量!
--注意2: 执行OPENDATASOURCE时需要确保要导入的Excel已关闭(EXCEL2010采用只读方式打开的话, 好像不会报错, 编辑模式会), 否则报错.
    SELECT [2010年1月临工工资] AS 代号 ,
F2 AS 姓名 ,
F3 AS 单位 ,
F17 AS 应发数
INTO #TEMP_临工雇员
FROM OPENDATASOURCE('MICROSOFT.ACE.OLEDB.12.0',
'Data Source=D:\2010年1月份临工工资.xls;Extended Properties=Excel 5.0')...[汇总明细表$] A
*/
-------------------------------------------------------------------


SELECT 月份 AS PROVIDE_DATE ,
姓名
AS DISPLAY_NAME ,
ISNULL(H.PERSON_CODE,
ISNULL(Z.PERSON_CODE,
ISNULL(GA.PERSON_CODE,
LA.PERSON_CODE)))
AS PERSON_CODE ,--代号
单位 AS PROVIDE_DEPT ,
应发数
AS SALARY_AMOUNT ,
备注
AS SOURCE
FROM ##TEMP_临工雇员_D2D119452A60497099FB24DF477EEB0A A WITH ( NOLOCK )
LEFT JOIN dbo.HRDATA H ON ( H.DISPLAY_NAME = REPLACE(A.姓名,
' ', '')
AND A.单位 LIKE '%雇员%'
)
ORDER BY PROVIDE_DATE ASC

--清理临时表数据
TRUNCATE TABLE ##TEMP_临工雇员_D2D119452A60497099FB24DF477EEB0A
DROP TABLE ##TEMP_临工雇员_D2D119452A60497099FB24DF477EEB0A
END

 

posted on 2011-01-27 15:16  jes  阅读(389)  评论(0)    收藏  举报

刷新页面返回顶部
 
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3