說到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 |
打開SQLServer客戶端鏈接要操做的數據庫引擎數據庫
右鍵要操做的數據庫,選擇任務--導入數據,第一次使用會彈出嚮導頁以下圖:c#
點下一步,通常要導入的數據都是excel,數據源咱們選擇Microsofy Excel
(不一樣版本會有些差別),api
瀏覽選擇要導入的excel文件;服務器
下一步選擇目標數據源選擇咱們的SQLServerapp
根據須要一直點下一步,須要注意在選擇表和數據源頁面,根據實際須要選擇對應的表,以及編輯列的映射,ide
最後點擊完成,導入數據。工具
此方法就是調用寫好的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;
}
複製代碼
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;
}
複製代碼
該方法對於須要批量導入數據,有須要對數據進行邏輯操做,影響多張表時,尤爲實用;本例以導入用戶資料爲例,親測因爲邏輯複雜在存儲過程當中使用遊標處理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();
}
複製代碼
以上幾種方式,我在實際工做中都有使用, 具體業務還須要根據狀況選擇合適的方案。 文檔編寫能力很差,有須要的能夠隨時交流。