2014-11-06 59 views
1

如果我有一個像與結構的數據表:如何更改DataTable結構,使列值在多個列中?

emp_num name status session_id 

    22 john  0  4 

    22 john  0  5 

    34 moh  1  3 

    35 Ran  0  3 

    35 Ran  0  4 

如何將其轉換爲數據表這樣的:

emp_num name status session_id1 session_id2 session_id3 session_id4 session_id5 

    22 john  0  0    0    0   1   1 

    34 moh  1  0    0    1   0   0 

    35 Ran  0  0    0    1   1   0 

我試圖創建循環自定義數據表但它不是通用的,我想要的東西如此通用,所以如果我添加更多的列或增加的會話數量,我不會超出範圍例外..

+1

我覺得有一些根本性的錯誤你的方法。如果您的員工和會話之間存在一對多關係,則需要有兩個表。一張僱員表,每個員工有一行,另一個表用於會話,每個會話有一行。每個會話記錄都應該有一個「emp_num」來將其鏈接回員工。 – Keith 2014-11-06 16:22:23

+0

@Keith:是啊,有兩個表,我讓兩個表之間的連接和設置的結果datatable.now,我想與 以下結構'emp_num名狀態session_id1 session_id2 session_id3 ...'的數量的報告列取決於session_id值 – 2014-11-09 07:18:12

回答

2
using System.Data; 
public static class DataTableExtensionMethods 
{ 
    public static DataTable TransposeIntegerColumnIntoColumns(this DataTable dt, int indexColumnToEstablishDuplicateRows, int integerColumnIdToTranspose, string transposedColumnName) 
    { 
     //Protection if the column to transpose is not an integer or doesn't exist 
     if (integerColumnIdToTranspose >= dt.Columns.Count) return null; 
     var columnDataType = dt.Columns[integerColumnIdToTranspose].DataType; 
     if (columnDataType != typeof(int)) return null; 

     //Get max sessions number 
     int maxColumnNumber = 0; 
     foreach (DataRow dr in dt.Rows) 
     { 
      int? number = dr.Field<int?>(integerColumnIdToTranspose); 
      if (number != null) 
      { 
       maxColumnNumber = Math.Max(maxColumnNumber, (int)number); 
      } 
     } 

     //Protection if there are zero rows or the maxColumnNumber is 0 
     if (dt.Rows.Count == 0 || maxColumnNumber == 0) return null; 

     //Make a copy of the table so we can remove duplicate rows and add the transposed columns 
     DataTable result = dt.Copy(); 

     //Add columns to store the session_ids 
     for (int i = 1; i <= maxColumnNumber; i++) 
     { 
      DataColumn dc = new DataColumn(transposedColumnName + i.ToString(), typeof(int)); 
      dc.DefaultValue = 0; 
      //Possibly make an overloaded method that supports inserting columns 
      result.Columns.Add(dc); 
     } 

     //Remove rows with duplicated employees 
     for (int i = 0; i < result.Rows.Count; i++) 
     { 
      int duplicateRow = GetRowIndexById(result, indexColumnToEstablishDuplicateRows, result.Rows[i][indexColumnToEstablishDuplicateRows].ToString(), i + 1); 
      if (duplicateRow > -1) 
      { 
       result.Rows.RemoveAt(duplicateRow); 
      } 
     } 

     //Populate the transposed columns with values in the integer Column To Transpose 
     foreach (DataRow dr in dt.Rows) 
     { 
      int? sessionNumber = dr.Field<int?>(integerColumnIdToTranspose); 
      if (sessionNumber == null) continue; 
      int rowIndex = GetRowIndexById(result, indexColumnToEstablishDuplicateRows, dr[indexColumnToEstablishDuplicateRows].ToString(), 0); 

      result.Rows[rowIndex][transposedColumnName + sessionNumber.ToString()] = 1; //or +=1 if you want to increment the number 
     } 

     //Remove the integerColumnIdToTranspose (again overload this method if you want to keep this column) 
     result.Columns.RemoveAt(integerColumnIdToTranspose); 

     return result; 
    } 

    //Net 4 implementation with optional parameter 
    //private static int GetRowIndexById(DataTable dt, int indexColumnToEstablishDuplicateRows, string id, int startLookAtRow = 0) 
    private static int GetRowIndexById(DataTable dt, int indexColumnToEstablishDuplicateRows, string id, int startLookAtRow) 
    { 
     for (int i = startLookAtRow; i < dt.Rows.Count; i++) 
     { 
      if (dt.Rows[i][indexColumnToEstablishDuplicateRows].ToString() == id) return i; 
     } 
     return -1; 
    } 
} 

調用代碼:

private void button1_Click(object sender, EventArgs e) 
{ 
    DataTable dt = GetData(); 
    DataTable result = dt.TransposeIntegerColumnIntoColumns(0, 3, "session_id"); 
} 

private DataTable GetData() 
{ 
    DataTable dt = new DataTable(); 
    dt.Columns.Add("emp_num", typeof(int)); 
    dt.Columns.Add("name"); 
    dt.Columns.Add("status", typeof(int)); 
    dt.Columns.Add("session_id", typeof(int)); 

    DataRow dr = dt.NewRow(); 
    dr["emp_num"] = 22; 
    dr["name"] = "John"; 
    dr["status"] = 0; 
    dr["session_id"] = 4; 
    dt.Rows.Add(dr); 

    dr = dt.NewRow(); 
    dr["emp_num"] = 22; 
    dr["name"] = "John"; 
    dr["status"] = 0; 
    dr["session_id"] = 5; 
    dt.Rows.Add(dr); 

    dr = dt.NewRow(); 
    dr["emp_num"] = 34; 
    dr["name"] = "Moh"; 
    dr["status"] = 1; 
    //dr["session_id"] = null; 
    dt.Rows.Add(dr); 

    dr = dt.NewRow(); 
    dr["emp_num"] = 35; 
    dr["name"] = "Ran"; 
    dr["status"] = 0; 
    dr["session_id"] = 3; 
    dt.Rows.Add(dr); 

    dr = dt.NewRow(); 
    dr["emp_num"] = 35; 
    dr["name"] = "Ran"; 
    dr["status"] = 0; 
    dr["session_id"] = 4; 
    dt.Rows.Add(dr); 

    return dt; 
} 

結果是:

enter image description here

+0

非常感謝您的努力。 但我達網絡使用3.5,所以我遇到這個錯誤'默認參數說明符不在第二方法'私有靜態詮釋GetRowIndexById permitted'(數據表DT,整數indexColumnToEstablishDuplicateRows,串ID,INT startLookAtRow = 0)' – 2014-11-10 08:46:04

+1

好的,拷貝/將數據表擴展方法類中的代碼粘貼到您的項目中,我將它與.Net 3.5兼容:) – 2014-11-10 09:03:39

+0

我得到以下異常:'不能將DBNull.Value轉換爲鍵入'System.Int32'。請使用可空類型',所以我編輯以下行'int sessionNumber = dr.Field (integerColumnIdToTranspose)== null? 0:dr.Field (integerColumnIdTo',但我得到另一個異常'列「session_id0」不屬於表.' – 2014-11-10 09:47:17