在很多情况下,应用程序都需要实现excel数据导入功能,数据如果只有几十条,或上百条,甚至上千条,速度还好。

  但是不仅如此,如果客户提供给你的excel本身存在着重复数据,或是excel中的某些数据已经在数据库存在,那这时,在向数据库插入数据前你还得判重,如果不存在才进行导入

通常,我们第一步就会通过上传的方式把excel中的数据读到内存,然后通过循环的方式得出一条一条数据,接着对于每条数据用关键字段去往数据库中进行一次查重,若存在则不做事情,若

不存在则向数据库中插入一条数据。这样一来,我们每一条数据都会与数据库打两次交道,众所周知,每连接一次数据库那是需要时间的,次数一多相当影响性能。若是成千上万条数据的话,可

想而知,这个导入过程会有多慢,尤其是Web应用程序,很有可能在我的请求还没执行完,突然程序就被终止了。

当然,还有个办法,就是拼SQL,每循环一条数据,首先判断,若不重复,我写一条SQL语句保存在某个变量中,直到循环到最后一条,可能会拼出多条Insert语句,最后送到数据库一次执

行,但是大家有没有想过,一旦数据量过大,几万,或几十万条数据拼成的字符串可想而知会有多长,送到数据库就会有被截断的可能。更何况还是逃离不了每次都要查询重复的惨况。

  一般来说,SQL语句离数据库端越近,执行效率越高,有没有可能,我把所要插入的数据集合一次性送给数据库,让判断重复,插入,返回重复数据的工作统统由数据库来执行呢?这样我只

要与数据库打一次交道,等待数据库给我结果就行。那么接下来就是我要讲到的利用表值参数来完成这一功能。

  由于为了讲述,例子中的表都比较简单

  1.首先我们来创建一张表(建库的过程在这里我就不说明了,为了大家看得清晰,尽量去除了无关的脚本行)

  1. CREATE TABLE [dbo].[BulkTestTable](
  2. [Id] [int] NOT NULL,
  3. [UserName] [nvarchar](32) NULL,
  4. [Pwd] [varchar](16) NULL,
  5. PRIMARY KEY CLUSTERED
  6. (
  7. [Id] ASC
  8. )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
  9. ) ON [PRIMARY]
  10.  
  11. GO

2.创建表值类型

  1. USE [BulkTestDB]
  2. GO
  3.  
  4. /****** Object: UserDefinedTableType [dbo].[BulkTestTableType] Script Date: 07/08/2015 16:04:38 ******/
  5. CREATE TYPE [dbo].[BulkTestTableType] AS TABLE(
  6. [Id] [int] NULL,
  7. [UserName] [nvarchar](32) NULL,
  8. [Pwd] [varchar](16) NULL
  9. )
  10. GO

3.写批量插入的存储过程

  1. CREATE procedure [dbo].[usp_BulkTestTable_Import]
    (@paratable as BulkTestTableType readonly) --此处的BulkTestTableType就是上面所定义的表类型,实际不用对它进行操作,只需要在程序中传入一个表给它,然后从它里面进行读取
  2.  
  3. AS
  1. Insert INTO dbo.BulkTestTable(Id,UserName,Pwd)
    select * from @paratable A
    WHERE Not EXISTS(select B.Id from BulkTestTable B WHERE B.Id=A.Id)
  2.  
  3. 7 SELECT * from @paratable A WHERE EXISTS (select B.Id from BulkTestTable B WHERE B.Id=A.Id) --查询出重复的记录
    GO

在这里,我的Id不是自动增长的,仅仅是主键而已,所以这里通过Id来判断记录是否唯一或重复

接下来在C#代码里面写一个导入方法,调用这个存储过程。

  1. 这里的参数dt就是我们导入excel时生成的DataTable,这个DataTable的表结构也就是列要与我们定义的表值“BulkTestTableType”结构相同,返回值就是我们所要的重复记录
  1. public static DataSet BatchInsert(DataTable dt)
  2. {
  3. SqlParameter parameter = new SqlParameter("@paratable",dt);
  4. parameter.SqlDbType = SqlDbType.Structured;
  5. parameter.TypeName = "BulkTestTableType"; //这里的类型名称应与我们定义的表值名称相同
  6. SqlParameter[] sqlParameters = new SqlParameter[] { parameter };
  7. return SqlHelper.RunProcedure(CommandType.StoredProcedure, "usp_BulkTestTable_Import", sqlParameters);
  1. }

以上就是完整的代码,当然,怎么在内存中创建表,怎么写数据库访问方法我这里就不说明了,大家都知道。小白写文章,大家共同交流,勿喷

在C#应用程序中,利用表值参数过滤重复,批量向数据库导入数据,并且返回重复数据的更多相关文章

  1. Android中利用ant进行多渠道循环批量打包

    公司负责Android开发的小伙伴学习能力稍微偏弱,交代给他的自动化打包的任务,弄了好久依然没有成效.无奈只好亲自出手. 没有想到过程很顺利,我完全按照如下文章的步骤进行: 主要参考: Android ...

  2. 学习Shell脚本编程(第3期)_在Shell程序中使用的参数

    位置参数 内部参数 如同ls命令可以接受目录等作为它的参数一样,在Shell编程时同样可以使用参数.Shell程序中的参数分为位置参数和内部参数等. 3.1 位置参数 由系统提供的参数称为位置参数.位 ...

  3. 3、在Shell程序中使用的参数

    学习目标位置参数内部参数 如同ls命令可以接受目录等作为它的参数一样,在Shell编程时同样可以使用参数.Shell程序中的参数分为位置参数和内部参数等. 12-3-1 位置参数由系统提供的参数称为位 ...

  4. 将应用程序中的一些参数写到xml配置文件中

    最近碰到一个问题,需要将程序中的一些基本参数写到xml文件中,虽然网上有好多现成的代码,但是觉得对xml不熟悉,果断就研究了一下.先说一下大体思路吧,我设计了一个用来读取和回填的类,然后定义了一个接口 ...

  5. SQLServer使用表值参数,高性能批量插入数据

    记得前段时间帮同事写了个解析账号并入库的小工具,来批量导入账号信息,账号量相当大,程序每读取一条记录便执行一次insert来插入数据,整整跑了一下午才把账号全部入库. 今天又接到同事类似的需求,不过这 ...

  6. python中利用上下文管理器来实现mysql数据库的封装

    from pymysql import connect class DB(object): def __init__(self, password, database): # 1.连接数据库 self ...

  7. sql server中新增一条数据后返回该数据的ID

    开发中遇到的问题:在新增一条数据后往往不需要返回该数据的ID,但是有的时候可能需要返回该数据的ID以便后面的编程使用. 在这里介绍两种方法: 其一:使用存储过程: create procedure a ...

  8. 微信小程序中利用时间选择器和js无计算实现定时器(将字符串或秒数转换成倒计时)

    转载注明出处 改成了一个单独的js文件,并修改代码增加了通用性,点击这里查看 今天写小程序,有一个需求就是用户选择时间,然后我这边就要开始倒计时. 因为小程序的限制,所以直接选用时间选择器作为选择定时 ...

  9. 在WPF应用程序中利用IEditableObject接口实现可撤销编辑的对象

    这是我辅导的一个项目开发中的例子,他们是用WPF做界面开发,在学习了如何使用MVVM来实现界面与逻辑的分离,并且很好的数据更新之后,有一个疑问就是,这种双向的数据更新确实很不错,但如果我们希望用户可以 ...

随机推荐

  1. 未在本地计算机上注册“microsoft.ACE.oledb.12.0”提供程序的解决方法

    在win7 操作系统中SQL2008导入excel2007 出现: 未在本地计算机上注册“microsoft.ACE.oledb.12.0”提供程序 的解决方法: 出现这个原因是office 2007 ...

  2. windows服务与其他进程使用MemoryMappedFile

    首先,名字必须以Global\开头. 其次,需要配置权限 var rule = new AccessRule<MemoryMappedFileRights>("everyone& ...

  3. C# 进程间共享内存通信方式

    从别处看到一篇文章做进程间通信很好使,唯一的问题是,需要注意using的用法,Using有个用法3, using 语句允许程序员指定使用资源的对象应当何时释放资源.using 语句中使用的对象必须实现 ...

  4. Winfrom 基于TCP的Socket服务端 多线程(进阶版)

    using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; usin ...

  5. 【读】为什么BIO效率低下

    原因: 假如有10000个连接,4核CPU ,那么bio 就需要一万个线程,而nio大概就需要5个线程(一个接收请求,四个处理请求).如果这10000个连接同时请求,那么bio就有10000个线程抢四 ...

  6. 1.1 JAVA装箱和拆箱以及Java Number & Math&Character 类

    JAVA装箱和拆箱 从Java SE5开始就提供了自动装箱的特性,如果要生成一个数值为10的Integer对象,只需要这样就可以了.原文链接: http://www.cnblogs.com/dolph ...

  7. javaweb开发之get与post请求的区别

    GET和POST是HTTP请求的两种基本方法,要说它们的区别,接触过WEB开发的人都能说出一二. 最直观的区别就是GET把参数包含在URL中,POST通过request body传递参数. 你可能自己 ...

  8. 《Programming iOS 7》读书笔记 - 窗体大小与状态栏

    1.从iOS7开始,状态栏开始变为透明的,根识图占领了整个窗体,包括状态栏后面的20像素高的区域,这种样式无法被改变.iOS6的状态栏是不透明的,窗体的尺寸通常会比屏幕的尺寸要小,可以设置窗体的尺寸为 ...

  9. nodejs中创建web服务,监听本地IP

    nodejs官网例子 var http = require('http'); http.createServer(function (req, res) { res.writeHead(200, {' ...

  10. jQuery基础(常用插件 表单验证,图片放大镜,自定义对象级,jQuery UI,面板折叠)

    1.表单验证插件——validate   该插件自带包含必填.数字.URL在内容的验证规则,即时显示异常信息,此外,还允许自定义验证规则,插件调用方法如下:   $(form).validate({o ...