SQLServer数据批量导入的几种方式

SQLServer数据批量导入的几种方式

说到SQLServer 的数据批量导入,下面用经常使用的几种方式作下对比,后面详细介绍每种方式如何使用(本文的代码使用语言c#)sql

导入方式 是否需写代码 导入过程可否对数据加工 插入数据的速度 多表数据导入 是否必需写SQL语句
1.经过SQLServer客户端管理工具 F F F F
2.循环调用插入语句、或存储过程 T T T T
3.使用SqlBulkCopy T F F F
4.使用SQLServer表值参数 T T T T

1.经过SQLServer客户端管理工具

  1. 打开SQLServer客户端链接要操做的数据库引擎数据库

  2. 右键要操做的数据库,选择任务--导入数据,第一次使用会弹出向导页以下图:c#

  1. 点下一步,通常要导入的数据都是excel,数据源咱们选择Microsofy Excel(不一样版本会有些差别),api

  2. 浏览选择要导入的excel文件;服务器

  3. 下一步选择目标数据源选择咱们的SQLServerapp

  4. 根据须要一直点下一步,须要注意在选择表和数据源页面,根据实际须要选择对应的表,以及编辑列的映射,ide

  5. 最后点击完成,导入数据。工具

2.循环调用插入语句、或存储过程

此方法就是调用写好的sql语句或存储过程来循环的插入数据导数据库;根据须要能够在读取文件数据后,对数据进行校验和加工。性能

下面代码是一个循环插入的实现,若是须要输出导入进度能够用BackgroundWorker+ progressBar在页面上显示导入进度;ui

private int DataImport()
{
  if (File.Exists(path))
    File.Delete(path);
  int i = 0;
  // 打开数据库链接
  string strConn = System.Configuration.ConfigurationManager.AppSettings["SsConnString"];
  SqlConnection Coon = new SqlConnection(strConn);
  if (Coon.State.Equals(ConnectionState.Closed))
  {
    Coon.Open();
  }

  foreach (DataRow dr in m_dt.Rows)
  {
    i++;
    if (bkWorker.CancellationPending)
    {
      e.Cancel = true;
      return -1;
    }
    SqlParameter[] parms = {
      new SqlParameter("@Name", SqlDbType.VarChar, 32),                   
      new SqlParameter("@Sheng", SqlDbType.VarChar),
      new SqlParameter("@City", SqlDbType.VarChar),
      new SqlParameter("@Xian", SqlDbType.VarChar)
    };
    try
    {
      parms[0].Value = (dr["姓名"] + "").Trim();
      parms[7].Value = dr["省"] + "";
      parms[8].Value = dr["市"] + "";
      parms[9].Value = dr["县"] + "";

    }
    catch (Exception)
    {
      MessageBox.Show("确保数据表中的列名和模版中的一致!", "警告", MessageBoxButtons.OK, MessageBoxIcon.Warning);
      return -1;
    }

    try
    {
      SqlCommand Cmd = Tools.CreateCmd("P_Data_Import", parms, Conn);
      int iRet = Cmd.ExecuteNonQuery();
      if (iRet == 0)
      {
        continue;
      }
    }
    catch (Exception ex)
    {
      Tools.Log_Write("第" + (m_dt.Rows.IndexOf(dr)+1).ToString() + "行导入出错:" + ex.Message, "d:\\数据导入日志.txt");
      continue;
    }
  }
  if (MessageBox.Show("数据导入完成!,打开导入日志!", "提示") == DialogResult.OK)
  {
    this.buttonImport.Enabled = true;
    if (File.Exists(path))
      System.Diagnostics.Process.Start(path);
  }

  Conn.Close();
  return -1;
}
// 打开数据库链接
public static SqlConnection ReturnConn()
{
  string strConn = "server=数据库地址;uid=数据库帐号;pwd=密码;database=数据库名"
  SqlConnection Coon = new SqlConnection(strConn);
  if (Coon.State.Equals(ConnectionState.Closed))
  {
    Coon.Open();
  }
  return Coon;
}

// 执行带参数的存储过程
public static SqlCommand CreateCmd(string procName, SqlParameter[] prams, SqlConnection Conn)
{
  SqlConnection SqlConn = Conn;
  if (SqlConn.State.Equals(ConnectionState.Closed))
  {
    SqlConn.Open();
  }
  SqlCommand Cmd = new SqlCommand();
  Cmd.CommandType = CommandType.StoredProcedure;
  Cmd.Connection = SqlConn;
  Cmd.CommandText = procName;
  if (prams != null)
  {
    foreach (SqlParameter parameter in prams)
    {
      if (parameter != null)
      {
        Cmd.Parameters.Add(parameter);
      }
    }
  }
  return Cmd;
}
复制代码

3.使用SqlBulkCopy

下面以导入学生消课数据为例,导入数据的方法,关于SqlBulkCopy(官方解释:容许你使用其余源的数据有效地批量加载 SQL Server 表。)的使用能够到到网上搜索,资料一大堆,官方文档直统统车

首先要构造要导入数据格式的DataTable类型的对象(TransferData)、其次要设置和数据源的列映射关系

Stopwatch 用于计算导入数据耗费时间

private void InsertTwo()
{            
  OpenFileDialog fd = new OpenFileDialog();
  if (fd.ShowDialog() != DialogResult.OK)
  {
    return;
  }
  Stopwatch sw = new Stopwatch();
  //给datatable 构造Column
  DataTable dt = Tools.TransferData(fd.FileName, "sheet1","");
  dt.Columns.Add(xhFee);

  this.btn_Import.Enabled = false;

  string strConn = System.Configuration.ConfigurationManager.AppSettings["SsConnString"];
  using (SqlConnection conn = new SqlConnection(strConn))
  {
    SqlBulkCopy bulkCopy = new SqlBulkCopy(conn);
    bulkCopy.DestinationTableName = "T_FI_IncomeDetail";
    bulkCopy.BatchSize = dt.Rows.Count;
    //设置列对应关系
    bulkCopy.ColumnMappings.Add("辅导类型", "FdId");
    bulkCopy.ColumnMappings.Add("消耗课时或课次", "XhKeshi");
    bulkCopy.ColumnMappings.Add("消耗日期", "CreateTime");
    bulkCopy.ColumnMappings.Add("学生姓名", "Name");
    conn.Open();
    sw.Start();
    int totalRow = dt.Rows.Count;

    if (dt != null && dt.Rows.Count != 0)
    {
      dateTimeDelete.Value = Convert.ToDateTime(dt.Rows[0]["消耗日期"]);
      bulkCopy.WriteToServer(dt);
      sw.Stop();
    }
    MessageBox.Show(string.Format("插入{0}条记录共花费{1}毫秒", totalRow, sw.ElapsedMilliseconds));
  }

}

// 获取excel数据并填充到DataTable
public static TransferData(string excelFile, string sheetName,string strScreen)
{
  System.Data.DataTable dt = new System.Data.DataTable();
  try
  {
    //获取所有数据  
    string strConn = "Provider=Microsoft.Ace.Oledb.12.0;Data Source=" + excelFile + ";Extended Properties='Excel 12.0;HDR=YES;IMEX=1;'";

    OleDbConnection conn = new OleDbConnection(strConn);
    conn.Open();
    OleDbDataAdapter myCommand = null;
    myCommand = new OleDbDataAdapter("Select * from [Sheet1$] " + strScreen, strConn);
    myCommand.Fill(dt);

    conn.Close();

  }
  catch (Exception ex)
  {
    MessageBox.Show(ex.Message);
  }
  return dt;
}
复制代码

4.使用SQLServer表值参数

该方法对于须要批量导入数据,有须要对数据进行逻辑操做,影响多张表时,尤为实用;本例以导入用户资料为例,亲测因为逻辑复杂在存储过程当中使用游标处理2000条数据,2s就可彻底导入。

主要是应用了SQLServer的表类型参数,经过给存储过程传入表数据,让sql操做都在数据库中进行,提高操做性能。

首先要根据要在数据库 建立自定义表类型,建立语句格式以下:

CREATE TYPE [dbo].[UserInfo] AS TABLE(
	[Name] [varchar](32) NULL,
	[Code] [varchar](32) NULL,
	[Gender] [varchar](32) NULL,
	[Birthday] [datetime] NULL
)
复制代码

存储过程使用方式:UserInfo即为提早建立好的自定义表类型

create proc procName
(
	@DataTable UserInfo readonly
)
as
begin
-- 实现本身的逻辑对@DataTable的使用能够向普通表同样,
-- 建议 若是须要对@DataTable须要连表过滤数据,请使用临时表, 不然可能会提示 超出数据库设置的最大查询时间
--(在数据库引擎,右键属性--链接中能够查看使用查询调控器防止查询时间过长,不勾选默认30s),
-- 建议逻辑操做能放在代码中处理的,不要放在存储过程当中,为了减少数据库服务器压力

end
复制代码

代码调用实例:

private int DataImport1(object sender)
{
  Stopwatch sw = new Stopwatch();
  sw.Start();
  string path = "d:\\数据导入日志.txt";
  if (File.Exists(path))
    File.Delete(path);
  int count = m_dt.Rows.Count;
  SqlConnection Conn = SsZongs.ReturnConn();

  DataTable dt = new DataTable("userIfo");
  dt.Columns.Add("Name", typeof(string));
  dt.Columns.Add("Code", typeof(string));
  dt.Columns.Add("Gender", typeof(string));
  dt.Columns.Add("Birthday", typeof(DateTime));
  try
  {
    for (int i = 0; i < count; i++)
    {
      try
      {
        dt.Rows.Add((m_dt.Rows[i]["姓名"] + "").Trim(),
                    m_dt.Rows[i]["编号"].ToString(),
                    m_dt.Rows[i]["性别"].ToString(),
                    m_dt.Rows[i]["出生日期"]
                   );
      }
      catch (Exception)
      {
        MessageBox.Show("确保数据表中的列名和模版中的一致!", "警告", MessageBoxButtons.OK, MessageBoxIcon.Warning);
        return -1;
      }

    }
    Tools.insertTableToDB(dt, "procName");
  }
  catch (Exception ex)
  {
    Tools.Log_Write(ex.Message, "d:\\数据导入日志.txt");
  }
  finally
  {
    sw.Stop();
    if (MessageBox.Show("数据导入完成!耗时"+ sw.ElapsedMilliseconds + "毫秒,打开导入日志!", "提示") == DialogResult.OK)
    {
      this.buttonImport.Enabled = true;
      if (File.Exists(path))
        System.Diagnostics.Process.Start(path);
    }
  }

  return -1;
}

public static void insertTableToDB(System.Data.DataTable dt,string procName)
{
  SqlConnection sqlCon = SsZongs.ReturnConn();

  using (var cmd = new SqlCommand(procName, sqlCon))
  {
    cmd.CommandType = CommandType.StoredProcedure;

    var param = new SqlParameter("@DataTable", SqlDbType.Structured) { Value = dt };
    cmd.Parameters.Add(param);
    cmd.ExecuteNonQuery();
  }
  sqlCon.Close();

}
复制代码

总结

以上几种方式,我在实际工做中都有使用, 具体业务还须要根据状况选择合适的方案。 文档编写能力很差,有须要的能够随时交流。

相关文章
相关标签/搜索