原文:SQL Server大量数据秒级插入/新增/删除

1.快速保存,该方法有四个参数,第一个参数为数据库连接,第二个参数为需要保存的DataTable,该参数的TableName属性需要设置为数据库中目标数据表的表名,第三个参数为输出参数,如果保存过程中发生错误则错误信息会输出在这个参数里面,第四个参数为可选参数,是否保持连接为打开状态。

        /// <summary>
/// 快速保存数据,自动识别insert和update
/// </summary>
/// <param name="_sourceTable">需要保存的源数据表</param>
/// <param name="_sqlCon">数据库连接</param>
/// <param name="_errorMsg">输出参数,错误信息</param>
/// <param name="KeepConnectionAlive">是否保持连接,可选参数,默认否</param>
/// <returns></returns>
private bool BulkSave(DataTable _sourceTable, SqlConnection _sqlCon,out string _errorMsg, bool _keepConnectionAlive = false)
{
bool result = true;
_errorMsg = string.Empty;
DataTable sourceTable = _sourceTable.Copy();
if (string.IsNullOrEmpty(sourceTable.TableName))
{
_errorMsg = "数据源表的TableName属性不能为空!";
return false;
}
List<string> colList = new List<string>();
foreach (DataColumn col in sourceTable.Columns)
{
colList.Add(col.ColumnName);
}
int updateNum, insertNum;
updateNum = insertNum = 0;
try
{
#region
if (_sqlCon.State == ConnectionState.Closed)
{
_sqlCon.Open();
}
SqlCommand cmd = _sqlCon.CreateCommand();
StringBuilder sb = new StringBuilder();
DataTable pk = new DataTable();
string tempTableName = "#" + sourceTable.TableName;//#表名 为当前连接有效的临时表 ##表名 为全局有效的临时表
string tempTableFullCloumn = "";//临时表获取表结构命令字符串
string updateSetStr = "";//update set 命令字符串
string insertWhereStr = "";//insert 命令用来排除已经存在记录的 not exist 命令中where条件字符串
string insertColumnStr = "";//列名字符串
string tempColmunstr = "";//t.+列名 字符串 sb = new StringBuilder();
sb.AppendFormat(@"select a.name as Name,b.name as 'type',a.length as 'length' ,a.collation as 'collation' from syscolumns a
left join systypes b
on a.xtype = b.xtype
where colid in
(select colid from sysindexkeys
where id = object_id('{0}')
and indid =
(select indid from sysindexes
where name = (select name from sysobjects
where xtype='PK'
and parent_obj = object_id('{0}')
)
)
) and a.id = object_id('{0}');", sourceTable.TableName);
cmd.CommandText = sb.ToString();
pk.Load(cmd.ExecuteReader());//查询主键列表
#endregion #region
/* 利用传递进来的DataTable列名列表,从数据库的源表获取
* 临时表的表结构*/
for (int i = 0; i < colList.Count; i++)
{ /* 如果当前列是主键,set命令字符串跳过不作处理,
* 临时表获取表结构命令字符串不论何种情况都不跳过 */ if (pk.Select("Name= '" + (colList[i]) + "'").Length > 0)
{
string sql = string.Format("SELECT COLUMNPROPERTY(OBJECT_ID('{0}'), '{1}', 'IsIdentity')", sourceTable.TableName, colList[i]);
cmd.CommandText = sql;
bool flag = Convert.ToBoolean(cmd.ExecuteScalar());
if (!flag)
{
if (updateSetStr.Length > 0)
{
updateSetStr += ",";
}
if (insertColumnStr.Length > 0)
{
insertColumnStr += ",";
}
if (tempColmunstr.Length > 0)
{
tempColmunstr += ",";
}
updateSetStr += colList[i] + "= t." + colList[i];
insertColumnStr += colList[i];
tempColmunstr += colList[i];
}
}
else
{
if (updateSetStr.Length > 0)
{
updateSetStr += ",";
}
if (insertColumnStr.Length > 0)
{
insertColumnStr += ",";
}
if (tempColmunstr.Length > 0)
{
tempColmunstr += ",";
}
updateSetStr += colList[i] + "= t." + colList[i];
insertColumnStr += colList[i];
tempColmunstr += colList[i];
} if (i > 0)
{
tempTableFullCloumn += ",";
} tempTableFullCloumn += "s." + colList[i];
}
#endregion #region
sb = new StringBuilder();
sb.AppendFormat("select top 0 {0} into {1} from {2} s;", tempTableFullCloumn, tempTableName, sourceTable.TableName);
cmd.CommandText = sb.ToString();
cmd.ExecuteNonQuery();//创建临时表 /* 根据获得的目标表主键,来为SQL Server 系统中的临时表增加相应的非主键但是数据相等
* 的 影射列,因为有些系统的主键为自增类型,在调用bulk.WriteToServer方法的时候,自增主键会
* 在临时表中从0开始计算,没办法用临时表的主键和目标表的主键做 where 条件,故用影射列代替*/
for (int i = 0; i < pk.Rows.Count; i++)
{
if (i > 0)
{
insertWhereStr += " and ";
}
string newColName = pk.Rows[i]["name"].ToString() + "New";
sb = new StringBuilder();
switch (pk.Rows[i]["type"].ToString())
{
case "char":
case "varchar":
case "nchar":
case "nvarchar":
sb.AppendFormat("alter table {0} add {1} {2}({3}) ", tempTableName, newColName, pk.Rows[i]["Type"].ToString(), pk.Rows[i]["length"]);
break;
default:
sb.AppendFormat("alter table {0} add {1} {2} ", tempTableName, newColName, pk.Rows[i]["Type"].ToString());
break;
}
if (!(pk.Rows[i]["collation"] is DBNull))
{
sb.AppendFormat("COLLATE {0}", pk.Rows[i]["collation"]);
}
cmd.CommandText = sb.ToString();
cmd.ExecuteNonQuery(); sourceTable.Columns.Add(new DataColumn(newColName, sourceTable.Columns[pk.Rows[i]["name"].ToString()].DataType));
foreach (DataRow dr in sourceTable.Rows)
{
dr[newColName] = dr[pk.Rows[i]["name"].ToString()].ToString().Trim();
}
insertWhereStr += "t." + newColName + "=s." + pk.Rows[i]["name"];
} using (System.Data.SqlClient.SqlBulkCopy bulk = new System.Data.SqlClient.SqlBulkCopy(_sqlCon))
{
//string SQl = "select * from #bulktable ";
//DataTable tempx = new DataTable();
//cmd.CommandText = SQl;
//tempx.Load(cmd.ExecuteReader());
//_souceTable.Rows[0]["unit_name"] = string.Empty;
//_souceTable.Rows[1]["unit_name"] = string.Empty;
int colCount = sourceTable.Columns.Count;
foreach (DataRow row in sourceTable.Rows)
{
for (int i = 0; i < colCount; i++)
{
row[i] = row[i].ToString().Trim();
}
}
bulk.DestinationTableName = tempTableName;
bulk.BulkCopyTimeout = 36000;
try
{
bulk.WriteToServer(sourceTable);//将数据写入临时表
//string sql = "select * from #bulktable";
//SqlDataAdapter sda = new SqlDataAdapter(sql, _sqlCon);
//DataTable dt = new DataTable();
//sda.Fill(dt);
}
catch (Exception e)
{
_errorMsg = e.Message;
result = false;
//MessageBox.Show(e.Message);
//return e.Message.Trim();
}
}
#endregion #region
if (insertWhereStr.Equals(""))//如果不存在主键
{
sb = new StringBuilder();
sb.AppendFormat("insert into {0} select {1} from {2} s;", sourceTable.TableName, tempTableFullCloumn, tempTableName);
cmd.CommandText = sb.ToString();
insertNum = cmd.ExecuteNonQuery();//插入临时表数据到目的表
//_errorMsg = "1";
}
else
{
sb = new StringBuilder(); sb.AppendFormat("update {0} set {1} from( {2} t INNER JOIN {0} s on {3} );",
sourceTable.TableName, updateSetStr, tempTableName, insertWhereStr);
//cmd.CommandText = sb.ToString();
//Stopwatch sw = new Stopwatch();
//sw.Start(); //updateNum = cmd.ExecuteNonQuery();//更新已存在主键数据
//_errorMsg += "更新" + updateNum + "条记录";
//sw.Stop();
//sb = new StringBuilder();
sb.AppendFormat("insert into {0}({4}) select {1} from {2} t where not EXISTS(select 1 from {0} s where {3});",
sourceTable.TableName, tempColmunstr, tempTableName, insertWhereStr, insertColumnStr);
cmd.CommandText = sb.ToString();
//insertNum = cmd.ExecuteNonQuery();//插入新数据
//_errorMsg += "插入" + insertNum + "条记录";
//MessageBox.Show("共用时" + sw.Elapsed + "\n 共新增:" + insertNum + "条记录,更新:" + updateNum + "条记录!");
//return_str = "1";
var st = _sqlCon.BeginTransaction();
cmd.Transaction = st;
try
{
cmd.ExecuteNonQuery();
st.Commit();
}
catch (Exception ee)
{
_errorMsg += ee.Message;
result = false;
st.Rollback();
} }
#endregion
}
catch (Exception e)
{
_errorMsg = e.Message.Trim();
result = false;
}
finally
{
if (!_keepConnectionAlive && _sqlCon.State == ConnectionState.Open)
{
_sqlCon.Close();
}
}
return result;
}

2.快速删除,该方法有四个参数,第一个参数为数据库连接,第二个参数为需要删除的DataTable,该参数的TableName属性需要设置为数据库中目标数据表的表名,第三个参数为输出参数,如果删除过程中发生错误则错误信息会输出在这个参数里面,第四个参数为可选参数,是否保持连接为打开状态。

        /// <summary>
/// 快速删除
/// </summary>
/// <param name="_sourceTable">需要删除的源数据表</param>
/// <param name="_sqlCon">数据库连接</param>
/// <param name="_errorMsg">输出参数,错误信息</param>
/// <param name="_keepConnectionAlive">是否保持连接,可选参数,默认否</param>
/// <returns></returns>
private bool BulkDelete(DataTable _sourceTable, SqlConnection _sqlCon, out string _errorMsg, bool _keepConnectionAlive = false)
{
bool result = true;
_errorMsg = string.Empty;
DataTable sourceTable = _sourceTable.Copy(); string SQl = "";
DataTable pkTable = new DataTable();
DataSet ds = new DataSet();
string whereStr = string.Empty;
string colList = string.Empty;
if (string.IsNullOrEmpty(sourceTable.TableName))
{
_errorMsg += "数据源表的TableName属性不能为空!";
return false;
}
try
{
#region 检查数据表是否存在
SqlCommand sqlComm = _sqlCon.CreateCommand();
SqlDataAdapter sda = new SqlDataAdapter();
string tempTableName = "#" + sourceTable.TableName;
SQl = string.Format("select COUNT(*) from sysobjects where id = object_id(N'[{0}]') and OBJECTPROPERTY(id, N'IsUserTable') = 1", sourceTable.TableName);
sqlComm.CommandText = SQl;
if (_sqlCon.State != ConnectionState.Open)
{
_sqlCon.Open();
}
int count = Convert.ToInt32(sqlComm.ExecuteScalar());
#endregion if (count == 0)
{
_errorMsg += string.Format("在数据库中,找不到名为{0}的数据表!", sourceTable.TableName);
}
else
{
#region 获取主键信息
SQl = string.Format(@"select a.name as Name,b.name as 'type',a.length as 'length' ,a.collation as 'collation' from syscolumns a left join systypes b on a.xtype = b.xtype where colid in (select colid from sysindexkeys where id = object_id('{0}') and indid = (select indid from sysindexes where name = (select name from sysobjects where xtype='PK' and parent_obj = object_id('{0}')))) and a.id = object_id('{0}');", sourceTable.TableName);
sqlComm.CommandText = SQl;
sda.SelectCommand = sqlComm;
sda.Fill(ds, "pkTable");
pkTable = ds.Tables["pkTable"];
#endregion #region 生成where条件
foreach (DataColumn col in sourceTable.Columns)
{
colList += colList.Length == 0 ? col.ColumnName : "," + col.ColumnName;
} SQl = string.Format("select top 0 {0} into {1} from {2}", colList, tempTableName, sourceTable.TableName);
sqlComm.CommandText = SQl;
sqlComm.ExecuteNonQuery();
if (pkTable.Rows.Count <= 0)
{
_errorMsg += string.Format("获取{0}表主键信息失败,请重试或者检查数据库!", sourceTable.TableName); }
else
{
foreach (DataRow dr in pkTable.Rows)
{
string newColName = dr["name"].ToString() + "New";
/* 如果当前列是主键,set命令字符串跳过不作处理,
* 临时表获取表结构命令字符串不论何种情况都不跳过 */
SQl = string.Format("SELECT COLUMNPROPERTY(OBJECT_ID('{0}'), '{1}', 'IsIdentity')", sourceTable.TableName, dr["name"]);
sqlComm.CommandText = SQl;
bool flag = Convert.ToBoolean(sqlComm.ExecuteScalar());
switch (dr["type"].ToString())
{
case "char":
case "varchar":
case "nchar":
case "nvarchar":
SQl = string.Format("alter table {0} add {1} {2}({3}) ", tempTableName, newColName, dr["Type"].ToString(), dr["length"]);
break;
default:
SQl = string.Format("alter table {0} add {1} {2} ", tempTableName, newColName, dr["Type"].ToString());
break;
}
if (!(dr["collation"] is DBNull))
{
SQl = string.Format("{0} COLLATE {1}", SQl, dr["collation"]);
}
sqlComm.CommandText = SQl;
sqlComm.ExecuteNonQuery(); whereStr += string.IsNullOrEmpty(whereStr) ? string.Format("{0}.{2} in( select {1}.[{3}] from {1} )", sourceTable.TableName, tempTableName, dr["name"], newColName) : string.Format(" and {0}.{2} in( select {1}.[{3}] from {1} )", sourceTable.TableName, tempTableName, dr["name"], newColName);
sourceTable.Columns.Add(new DataColumn(newColName, sourceTable.Columns[dr["name"].ToString()].DataType));
foreach (DataRow row in sourceTable.Rows)
{
row[newColName] = row[dr["name"].ToString()].ToString().Trim();
}
}
}
}
#endregion #region 将数据放进临时表 SqlBulkCopy bulk = new SqlBulkCopy(_sqlCon);
bulk.DestinationTableName = tempTableName;
bulk.BulkCopyTimeout = 3600;
try
{
bulk.WriteToServer(sourceTable);
}
catch (Exception ee)
{
_errorMsg += ee.Message;
bulk.Close();
}
#endregion #region 开始删除
//SQl = string.Format("select * from {0}", tempTableName);
//sqlComm.CommandText = SQl;
//sda.SelectCommand = sqlComm;
//sda.Fill(ds, tempTableName);
SQl = string.Format(@" DELETE FROM {0} WHERE {1}", sourceTable.TableName, whereStr);
sqlComm.CommandText = SQl;
var tx = _sqlCon.BeginTransaction();
try
{
sqlComm.Transaction = tx;
count = sqlComm.ExecuteNonQuery();
tx.Commit();
_errorMsg += string.Format("应该删除{0}条记录\r\n共删除{1}条记录!", sourceTable.Rows.Count, count);
}
catch (Exception ee)
{
_errorMsg += ee.Message;
tx.Rollback();
}
#endregion
}
catch (Exception e)
{
_errorMsg += e.Message;
}
finally
{
if (_sqlCon.State == ConnectionState.Open && !_keepConnectionAlive)
{
_sqlCon.Close();
}
}
return result;
}

SQL Server大量数据秒级插入/新增/删除的更多相关文章

  1. Redis实战--使用Jedis实现百万数据秒级插入

    echo编辑整理,欢迎转载,转载请声明文章来源.欢迎添加echo微信(微信号:t2421499075)交流学习. 百战不败,依不自称常胜,百败不颓,依能奋力前行.--这才是真正的堪称强大!!! 当我们 ...

  2. SQL Server 大数据量批量插入

    private void AddShuJu_Click(object sender, RoutedEventArgs e) { Stopwatch wath = new Stopwatch(); wa ...

  3. 09Microsoft SQL Server 表数据插入,更新,删除

    Microsoft SQL Server 表数据插入,更新,删除 向表中插入数据 INSERT INTO insert into tb1 values(0004,'张凤凤') insert into ...

  4. SQL Server 变更数据捕获(CDC)监控表数据

    一.本文所涉及的内容(Contents) 本文所涉及的内容(Contents) 背景(Contexts) 实现过程(Realization) 补充说明(Addon) 参考文献(References) ...

  5. SQL Server 中 ROWLOCK 行级锁

    一.ROWLOCK的使用 1.ROWLOCK行级锁确保,在用户取得被更新的行,到该行进行更新,这段时间内不被其它用户所修改.因而行级锁即可保证数据的一致性,又能提高数据操作的并发性. 2.ROWLOC ...

  6. 《转》SQL Server 2008 数据维护实务

    SQL Server 2008 数据维护实务 http://blog.csdn.net/os005/article/details/7739553 http://www.cnblogs.com/xun ...

  7. 不同版本的SQL Server之间数据导出导入的方法及性能比较

    原文:不同版本的SQL Server之间数据导出导入的方法及性能比较 工作中有段时间常常涉及到不同版本的数据库间导出导入数据的问题,索性整理一下,并简单比较下性能,有所遗漏的方法也欢迎讨论.补充. 0 ...

  8. sql server迁移数据(文件组之间的互相迁移与 文件组内文件的互相迁移)

    转自:https://www.cnblogs.com/lyhabc/p/3504380.html?utm_source=tuicool SQLSERVER将数据移到另一个文件组之后清空文件组并删除文件 ...

  9. SQL Server 迁移数据到MySQL

    一.背景 由于项目开始时候使用的数据库是SQL Server,后来把存储的数据库调整为MySQL,所以需要把SQL Server的数据转移到MySQL:由于涉及的表比较多,所以想在MySQL中生成对应 ...

随机推荐

  1. Linux网卡驱动程序对ethtool的支持和实现

    Linux 的一个显著特点就是其强大的网络功能,Linux 几乎支持所有的网络协议,并在这些协议基础上提供了丰富的应用.对 Linux 网络管理的重要性不言而喻,这些管理依赖于网络工具,比如最常用的 ...

  2. vim使用的一些积累

    vi visual interfacevim vi improved vim模式:编辑模式(命令模式)输入模式末行模式 编辑模式下,zz保存并退出移动光标:(编辑模式)1.逐字符移动 h 左 l 右 ...

  3. linux备忘录-档案与文件系统的压缩与打包

    知识点 文件扩展名与压缩解压缩工具 .Z -> compress程序压缩的档案 .gz -> gzip程序压缩的档案 .bz2 -> bzip2程序压缩的档案 .tar -> ...

  4. 【Android】实验7 BindService模拟通信 截止提交日期2016.5.3

    实验7 BindService模拟通信 [目的] 实现启动端和BindService之间的双向通信 [要求] 1)   实现从启动端传递一个数据至BindService端: 2)   实现使用Bind ...

  5. ls目录结构

    命令ls ls -l = ll -l 详细信息-a 查看隐藏的文件或目录-d 只看目录本身,不列出目录下面的文件和目录 一起使用一般 ls -ld-t 以时间先后排序-i 显示文件节点-h 显示字节大 ...

  6. asp.net 存储过程 输出参数 取不到值

    这是MSDN上的明确解释:当您将 Command 对象用于存储过程时,可以将 Command 对象的 CommandType 属性设置为 StoredProcedure.当 CommandType 为 ...

  7. ubuntu系统更换源

    一:问题概述 ubuntu,我们在使用apt新装软件的时候,会使用官方的网站去下载软件,但是会因为国内的转接点太多,而导致下载的速度非常慢 ,我们可以通过换成一些中间的节点来进行下载,比如阿里源,中科 ...

  8. ftp无法连接的原因

    1.需求 记录碰到的ftp无法连接的原因 2.解决方案 .确认ftp服务开启. .确认21端口没有被占用. .确认有目录的执行权限. .确认配置文件中的目录读写权限正确. .关闭SELinux 修改/ ...

  9. Windows注册与删除mysql服务

    1.删除服务: (1)采用windows自带的服务管理工具:参考:http://www.cnblogs.com/qlqwjy/p/8010598.html sc delete MySQL57 (2)m ...

  10. (转)cygwin包管理器apt-cyg

    通过终端安装apt-cyg之前选要安装以下软件包 wget tar gawk bzip2 Cygwin终端安装 wget http://apt-cyg.googlecode.com/svn/trunk ...