1. 程式人生 > >如何用SqlBulkCopy完成未知列數和列名的資料表的採集

如何用SqlBulkCopy完成未知列數和列名的資料表的採集

SqlBulkCopy 很簡單也很好用, 但關鍵是當資料來源表非常靈活而多變時(事先不知道有多少列,也不知道每1列的列名), 如何來做這件事呢?

1. 寫入表設定為101列, 第1列為批次,每寫入一批資料作為一批;

2. 寫入表中的除batch之外的列均為 nvarchar(max);

3. 寫入資料時要將來源表中的表頭存放到另一張表中, 便於以後的匯出。

A. 測試資料準備

--1. 資料來源表
IF OBJECT_ID('source_table') IS NOT NULL
	DROP TABLE source_table
GO
CREATE TABLE source_table
(
	school NVARCHAR(100),
	account VARCHAR(200),
	cnt_ct  INT,
	createTime DATETIME
)
GO
INSERT INTO source_table
SELECT '春蘭小學','liuming',25,'2005-10-23' union
SELECT '春蘭大學','leaf',25,'2005-10-20'
GO
--2. 目標表
IF OBJECT_ID('target_table') IS NOT NULL
	DROP TABLE target_table
GO
CREATE TABLE target_table
(
	batch BIGINT,
	C1 NVARCHAR(MAX),
	C2 NVARCHAR(MAX),
	C3 NVARCHAR(MAX),
	C4 NVARCHAR(MAX),
	C5 NVARCHAR(MAX),
	C6 NVARCHAR(MAX),
	C7 NVARCHAR(MAX),
	C8 NVARCHAR(MAX),
	C9 NVARCHAR(MAX),
	C10 NVARCHAR(MAX)
)
GO
--3. 表頭表
IF OBJECT_ID('header_table') IS NOT NULL
	DROP TABLE header_table
GO
CREATE TABLE header_table
(
	id BIGINT IDENTITY(1,1),
	batch BIGINT,
	columnName NVARCHAR(MAX),
	columnIndex int
)
GO

2. DBHelper: 見: 點選開啟連結

3. 測試控制檯程式:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.SqlClient;
using System.Collections;
using System.Data;
using Common;

namespace ConsoleApplication1
{
    class Program_6
    {
        static void Main(string[] args)
        {
            SqlConnection ConnectionNew = new SqlConnection("Data Source=leaf-home\\sqlserver2005;Initial Catalog=Test;Persist Security Info=True;User ID=??;Password=??");
            SqlConnection ConnectionOld = new SqlConnection("Data Source=leaf-home\\sqlserver2005;Initial Catalog=Test;Persist Security Info=True;User ID=??;Password=??");
            try
            {
                ConnectionNew.Open();
                ConnectionOld.Open();

                //1.在舊錶中,用SqlDataAdapter讀取出資訊  
                string SQL = "select school 學校,account 賬號,cnt_ct 簡訊量, createTime 建立日期 from source_table";

                DataTable dt = Common.DBHelper.GetDataTableBySql(SQL);      //資料來源表
                DataTable dt_clone = dt.Clone();                            //複製表, 用於加多一列, 並將其它列改為String型別

                long batch = 3;
                DataColumn dcBatch = new DataColumn("batch");
                dcBatch.DataType = typeof(long);// Type.GetType("System.Int64");
                dt_clone.Columns.Add(dcBatch);
                dcBatch.SetOrdinal(0);  //設定為第1列 非常重要

                for (int i = 1; i < dt.Columns.Count; i++)
                {
                    dt_clone.Columns[i].DataType = Type.GetType("System.String");
                }

                foreach (DataRow dr in dt.Rows)
                {
                    DataRow dr_clone = dt_clone.NewRow();
                    foreach (DataColumn dc in dt.Columns)
                    {

                        dr_clone[dc.ColumnName] = dr[dc.ColumnName];
                    }
                    dr_clone[0] = batch;
                    dt_clone.Rows.Add(dr_clone);
                }
                //將表頭存入表頭表中, 方便以後匯出時使用
                int dcIdx = 1;
                foreach (DataColumn dc in dt.Columns)
                {
                    SqlParameter[] spArr = new SqlParameter[]{
                        new SqlParameter("columnName", dc.ColumnName),
                        new SqlParameter("batch",Convert.ToInt64(batch)).SetDbType(DbType.Int64),
                        new SqlParameter("columnIndex",dcIdx++)};

                    string sql = @"
if not exists(select 1 from header_table where 
[email protected]
and [email protected]) begin insert into header_table (columnName,batch,columnIndex) select @columnName,@batch,@columnIndex end "; Common.DBHelper.ExecuteNonQuery(sql, spArr); } //2.初始化SqlBulkCopy物件,用新的連線作為引數。 SqlBulkCopy bulkCopy = new SqlBulkCopy(ConnectionNew); //3.寫對應關係。如舊錶的People列的資料,對應新表Human列,那麼就寫bulkCopy.ColumnMappings.Add("People","Human") //如果兩張表的結構一樣,那麼對應關係就不用寫了。 //我是用雜湊表儲存對應關係的,雜湊表作為引數到傳入方法中,key的值用來儲存舊錶的欄位名,VALUE的值用來儲存新表的值 Hashtable ht = new Hashtable(); ht.Add("batch", "batch"); int j = 1; foreach (DataColumn dc in dt.Columns) { ht.Add(dc.ColumnName, "C" + (j++).ToString()); } foreach (string str in ht.Keys) { bulkCopy.ColumnMappings.Add(str, ht[str].ToString()); } //4.設定目標表名 bulkCopy.DestinationTableName = "target_table"; //額外,可不寫:設定一次性處理的行數。這個行數處理完後,會激發SqlRowsCopied()方法。預設為1 bulkCopy.NotifyAfter = 1; //額外,可不寫:設定激發的SqlRowsCopied()方法,這裡為bulkCopy_SqlRowsCopied bulkCopy.SqlRowsCopied += new SqlRowsCopiedEventHandler(bulkCopy_SqlRowsCopied); //OK,開始傳資料! bulkCopy.WriteToServer(dt_clone); Console.Write("傳輸完畢!"); Console.Read(); } catch (Exception ex) { Console.Write(ex.Message); Console.Read(); } finally { ConnectionNew.Close(); ConnectionOld.Close(); } } //激發的方法寫在外頭 private static void bulkCopy_SqlRowsCopied(object sender, SqlRowsCopiedEventArgs e) { //執行的內容。 //這裡有2個元素值得拿來用 //e.RowsCopied, //返回數值型別,表示當前已經複製的行數 //e.Abort, //用於賦值true or false,用於停止賦值的操作 Console.WriteLine("當前已複製的行數:" + e.RowsCopied); } } }


將上面的程式碼 batch 改為3(4個欄位), 4 (3個欄位), 執行兩次後結果如下:

很明顯, 在任意變化的情況下, 為我們實現了資料的轉移。

當然, 實際的資料採集過程, 可能還會複雜一些:比如同一批資料會有多次傳入。不過大體的思路可以定下來的了。



相關推薦

如何用SqlBulkCopy完成未知列名資料採集

SqlBulkCopy 很簡單也很好用, 但關鍵是當資料來源表非常靈活而多變時(事先不知道有多少列,也不知道每1列的列名), 如何來做這件事呢? 1. 寫入表設定為101列, 第1列為批次,每寫入一批資料作為一批; 2. 寫入表中的除batch之外的列均為 nvarcha

MySQL--修改資料6:修改定義更名資料

修改列定義和更名資料表把某一列移動到指定位置:ALTER TABLE users2 MODIFY id SMALLINT UNSIGNED NOT NULL FIRST; // 末尾也可加 (AFTER 列名) 放在某一列之後修改某一列的定義型別:ALTER TABLE us

Java獲得數據庫查詢結果的,打印查詢結果

rman execute .get name 數據庫查詢 隨筆 while cti etc Java連接數據庫及簡單操作見我以前的一篇隨筆:http://www.cnblogs.com/meitian/p/5036332.html 一、獲取查詢結果的行數和列數 查詢結果

子類對父類的調,主要是參方法調

繼承 bsp pri load china 類的方法 調用父類 class sub #子類調用父類的方法 class Vehichle: Country=‘china‘ #名字=‘ales‘不好這樣 def __init__(self,name,s

深入淺出SQL Server 2008 分區函分區

準備 引用 數據類型 發布 回復 不同 con 否則 stc http://www.cnblogs.com/zhijianliutang/archive/2012/10/28/2743722.html 我們數據量比較大的時候,我們需要將大型表拆分為多個較小的表,則

c++基礎語法之構造函初始化

沒有 參數表 編譯器 ima http 構造函數 struct 轉換 顯示 筆者剛系統的重學了c++的語法,看到構造函數和初始化表這塊,發現這塊語法有點復雜且很雜,怕以後忘記,於是寫下此篇,以後回憶之用。 c++構造函數 3、構造函數(constructor

最快速度檢視windows系統 IIS 併發連線共享資料夾最大連線的方法

windows系統 版本分伺服器版和家用版/企業版,比如   windows 7 是家用版/企業版,對應windows 2008/2008R2就是伺服器版。   家用版/企業版的共享資料夾連線和IIS都有最大限制,當同時訪 問人數過多,會導致其他人連不上目標機器。   於

單元二:建立維護資料

1、   一個關係由一個二維表表示 2、   二維表中的每一列稱為關係的一個屬性,即欄位 3、   二維表中的每一行的所有資料稱為一個元組,相當一個記錄,代表一個實體 4、   能唯一標識一個元組的一個或若干個屬性的集合稱為

mysql約束修改資料

FOREIGN KEY(外來鍵約束)要求: 1.父表子表必須使用相同的儲存引擎,而且禁止使用臨時表。 2.資料表的儲存引擎只能為INNODB. 3.外來鍵列於參照列必須具有相似的資料型別。數字長度和是否有符號位必須相同; 字元的長度可以不同。 4.外來鍵列和參照列必須建立索

MySQL 約束修改資料

1.     FOREIGN KEY(外來鍵約束):保持資料的一致性,完整性。實現資料表的一對一,一對多的關係。 a)     父表(子表所參照的表)和子表(具有外來鍵列的表)必須使用相同的儲存引擎,

----遞歸函棧的操作實現逆序一個棧

color return -- 並且 壓入 但是 遞歸 tel 結構 用遞歸函數和棧的操作實現逆序一個棧   一個棧依次壓入1、2、3、4、5,那麽從棧頂到棧底分別為5、4、3、2、1,將這個棧轉置後,從棧頂到棧底為1、2、3、4、5,也就是實現棧中元素的逆序,但是只能

算法:兩個棧來實現一個隊完成的PushPop操作。 隊中的元素為int類型。《劍指offer》

pack 代碼 exception 隊列 imp scrip 入棧 return tro 算法:用兩個棧來實現一個隊列,完成隊列的Push和Pop操作。 隊列中的元素為int類型。《劍指offer》 利用棧來進行操作,代碼註釋寫的比較清楚:首先判斷兩個棧是否是空的:

題目描述 在一個二維組中(每個一維組的長度相同),每一行都按照從左到右遞增的順序排序,每一都按照從上到下遞增的順序排序。請完成一個函,輸入這樣的一個二維一個整數,判斷組中是否含有該整數。

這樣的 -i 一個 整數 描述 輸入 遞增 lse i+1 題目描述 在一個二維數組中(每個一維數組的長度相同),每一行都按照從左到右遞增的順序排序,每一列都按照從上到下遞增的順序排序。請完成一個函數,輸入這樣的一個二維數組和一個整數,判斷數組中是否含有該整數。 1

python:Redis完成發布訂閱

sage host cal ins ESS div 安裝 def lis 安裝: pip install redis    發布文件: # coding:utf-8 import redis import json class RedisHelper():

面試題9-兩個棧來實現一個隊完成的PushPop操作

ati import str highlight print row pty 用兩個棧 div 題目 用兩個棧來實現一個隊列,完成隊列的Push和Pop操作。 隊列中的元素為int類型。 思路: 一個棧壓入元素,而另一個棧作為緩沖,將棧1的元素出棧後壓入棧2中

VBA得到EXCEL表格中的行

方法3:   ActiveSheet.Cells.SpecialCells(xlCellTypeLastCell).Row   ActiveSheet.Cells.SpecialCells(xlCellTypeLastCell).Column   缺點:在工作表進行對刪除或清除操作時也會變得比實際情況大。方法

C語言中的函式列印乘法口訣,行可以任意輸入

#define _CRT_SECURE_NO_WARNINGS #include<stdio.h> void print_table(int line) { int i = 0;

exit庫函_exit系統調對標準輸出的影響

eno 標準 代碼 for sizeof pan type lob int #include <stdio.h> #include <unistd.h> #include <sys/types.h> #include <stdli

組、鏈、堆棧

數組 經典 clas 刪除 概念 連續 con 一個 這樣的 鏈表,隊列,堆棧的區別1、棧是個有底的口袋,像襪子。隊列是沒底的口袋,像通心粉。所以:棧的特點是先進後出,隊列的特點是先進先出。2、主要區別是適用的地方不一樣, 鏈表實際上可以認為是一種數據的物理組織形式

js new一個函直接調的差別

.get new javascrip 引用類型 類型 彈出 color pos 不同 用new和調用一個函數的差別:假設函數返回值是一個值類型(Number、String、Boolen)時,new函數將會返回這個函數的實例對象。而假設這個函數的返回值是一個引用類型(