原文: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. STL之queue&stack使用简介

       queue 队列也是一个线性存储表,与后进先出的堆栈不同,元素数据的插入在表的一端进行,在另一端删除,从而构成了一个先进先出(First In First Out) 表.插入一端称为队尾,删除一 ...

  2. 用Linkedhashmap的LRU特性及SoftReference软引用构建二级缓存

    LRU: least recently used(近期最少使用算法).LinkedHashMap构造函数可以指定其迭代顺序:LinkedHashMap(int initialCapacity, flo ...

  3. 团队Alpha版本冲刺(四)

    目录 组员情况 组员1(组长):胡绪佩 组员2:胡青元 组员3:庄卉 组员4:家灿 组员5:凯琳 组员6:丹丹 组员7:何家伟 组员8:政演 组员9:鸿杰 组员10:刘一好 组员:何宇恒 展示组内最新 ...

  4. (转)详解JavaScript模块化开发

    https://segmentfault.com/a/1190000000733959 什么是模块化开发? 前端开发中,起初只要在script标签中嵌入几十上百行代码就能实现一些基本的交互效果,后来j ...

  5. Linux下磁盘管理

    设置密码mkpasswdmkpasswd -s 0mkpasswd -s 0 -1 15 规定密码的长度 1. 查看磁盘或者目录的容量df 查看磁盘各分区使用情况 不加参数以k为单位 df -i in ...

  6. 【bzoj2396】神奇的矩阵 随机化

    题目描述 给出三个行数和列数均为N的矩阵A.B.C,判断A*B=C是否成立. 输入 题目可能包含若干组数据.对于每组数据,第一行一个数N,接下来给出三个N*N的矩阵,依次为A.B.C三个矩阵. 输出 ...

  7. flutter channel master

    flutter可能是未来跨平台开发的又一技术框架,那么对于一个app,我们不可能完全用flutter来开发,那么就意味着我们需要在已有的Android和iOS代码中去集成flutter.目前这一技术还 ...

  8. 为基于busybox根文件系统的ARM嵌入式Linux交叉编译dropbear使能SSH

    原创作品,允许转载,转载时请务必以超链接形式标明文章.作者信息和本声明,否则将追究法律责任. 最近使用busybox为基于ARM的板卡定制了一个极简单的根文件系统,由于busybox仅支持telnet ...

  9. DP———5.拣馅饼(记忆化搜索,得到最大值)

    都说天上不会掉馅饼,但有一天gameboy正走在回家的小径上,忽然天上掉下大把大把的馅饼.说来gameboy的人品实在是太好了,这馅饼别处都不掉,就掉落在他身旁的10米范围内.馅饼如果掉在了地上当然就 ...

  10. getElementsByName

    name属性,name属性是input标签的内建属性,早期浏览器的getElementsByName方法是为了方便的获取用户的输入.由于name只是input的内建属性,其它标签没有,所以getEle ...