2009-03-20 23 views
35

Hãy T1 và T2 là DataTable s với các lĩnh vực sauNội tham gia của DataTables trong C#

T1(CustID, ColX, ColY) 

T2(CustID, ColZ) 

tôi cần bảng doanh

TJ (CustID, ColX, ColY, ColZ) 

Làm thế nào điều này có thể được thực hiện trong mã C# một cách đơn giản ? Cảm ơn.

Trả lời

46

Nếu bạn được phép sử dụng LINQ, hãy xem ví dụ sau. Nó tạo ra hai DataTables với các cột nguyên, điền chúng với một số bản ghi, kết hợp chúng bằng cách sử dụng truy vấn LINQ và xuất chúng ra Console.

DataTable dt1 = new DataTable(); 
    dt1.Columns.Add("CustID", typeof(int)); 
    dt1.Columns.Add("ColX", typeof(int)); 
    dt1.Columns.Add("ColY", typeof(int)); 

    DataTable dt2 = new DataTable(); 
    dt2.Columns.Add("CustID", typeof(int)); 
    dt2.Columns.Add("ColZ", typeof(int)); 

    for (int i = 1; i <= 5; i++) 
    { 
     DataRow row = dt1.NewRow(); 
     row["CustID"] = i; 
     row["ColX"] = 10 + i; 
     row["ColY"] = 20 + i; 
     dt1.Rows.Add(row); 

     row = dt2.NewRow(); 
     row["CustID"] = i; 
     row["ColZ"] = 30 + i; 
     dt2.Rows.Add(row); 
    } 

    var results = from table1 in dt1.AsEnumerable() 
       join table2 in dt2.AsEnumerable() on (int)table1["CustID"] equals (int)table2["CustID"] 
       select new 
       { 
        CustID = (int)table1["CustID"], 
        ColX = (int)table1["ColX"], 
        ColY = (int)table1["ColY"], 
        ColZ = (int)table2["ColZ"] 
       }; 
    foreach (var item in results) 
    { 
     Console.WriteLine(String.Format("ID = {0}, ColX = {1}, ColY = {2}, ColZ = {3}", item.CustID, item.ColX, item.ColY, item.ColZ)); 
    } 
    Console.ReadLine(); 

// Output: 
// ID = 1, ColX = 11, ColY = 21, ColZ = 31 
// ID = 2, ColX = 12, ColY = 22, ColZ = 32 
// ID = 3, ColX = 13, ColY = 23, ColZ = 33 
// ID = 4, ColX = 14, ColY = 24, ColZ = 34 
// ID = 5, ColX = 15, ColY = 25, ColZ = 35 
+4

Điều này cuối cùng có hiệu quả đối với tôi, nhưng tôi đã dành hơn một giờ cho nó, với ngoại lệ "Specified cast not valid", nghi ngờ sự tỉnh táo của tôi, cho đến khi tôi thay đổi từ (int) table1 ["field"] thành Convert.ToInt32 (table1 ["field"]). – CindyH

+1

@CindyH, cảm ơn rất nhiều vì bình luận của bạn, nó đã giúp tôi tiết kiệm thời gian. Tôi đoán điều này là do System.Data.DataTypes, trong đó int không được bao gồm, nhưng Int32 là. Danh sách tất cả DataTypes tại đây: https://msdn.microsoft.com/en-us/library/system.data.datacolumn.datatype(v=vs.110).aspx – FrenkyB

27

Tôi muốn có chức năng tham gia các bảng mà không yêu cầu bạn xác định các cột bằng bộ chọn loại ẩn danh, nhưng gặp khó khăn trong việc tìm kiếm bất kỳ. Cuối cùng tôi phải tự làm. Hy vọng rằng điều này sẽ giúp bất cứ ai trong tương lai những người tìm kiếm này:

private DataTable JoinDataTables(DataTable t1, DataTable t2, params Func<DataRow, DataRow, bool>[] joinOn) 
{ 
    DataTable result = new DataTable(); 
    foreach (DataColumn col in t1.Columns) 
    { 
     if (result.Columns[col.ColumnName] == null) 
      result.Columns.Add(col.ColumnName, col.DataType); 
    } 
    foreach (DataColumn col in t2.Columns) 
    { 
     if (result.Columns[col.ColumnName] == null) 
      result.Columns.Add(col.ColumnName, col.DataType); 
    } 
    foreach (DataRow row1 in t1.Rows) 
    { 
     var joinRows = t2.AsEnumerable().Where(row2 => 
      { 
       foreach (var parameter in joinOn) 
       { 
        if (!parameter(row1, row2)) return false; 
       } 
       return true; 
      }); 
     foreach (DataRow fromRow in joinRows) 
     { 
      DataRow insertRow = result.NewRow(); 
      foreach (DataColumn col1 in t1.Columns) 
      { 
       insertRow[col1.ColumnName] = row1[col1.ColumnName]; 
      } 
      foreach (DataColumn col2 in t2.Columns) 
      { 
       insertRow[col2.ColumnName] = fromRow[col2.ColumnName]; 
      } 
      result.Rows.Add(insertRow); 
     } 
    } 
    return result; 
} 

Một ví dụ về cách bạn có thể sử dụng này:

var test = JoinDataTables(transactionInfo, transactionItems, 
       (row1, row2) => 
       row1.Field<int>("TransactionID") == row2.Field<int>("TransactionID")); 

Một caveat: Đây chắc chắn là không được tối ưu hóa, vì vậy hãy lưu tâm khi nhận được để đếm hàng trên 20k. Nếu bạn biết rằng một bảng sẽ lớn hơn bảng kia, hãy thử đặt cái đầu tiên nhỏ hơn và cái lớn hơn một giây.

+0

Có cách nào để sửa đổi nó để có thể chỉ định toán tử AND hoặc OR giữa nhiều điều kiện "tham gia"? – Igor

+0

Cách dễ nhất là không thay đổi mã và chỉ đóng gói tất cả các điều kiện của bạn vào một tham gia trong điều kiện. Ví dụ: 'row1.Field (" Id ") == row2.Field (" Id ") || row1.Field ("CustId") == row2.Field ("CustId") ' – Bognar

+0

Nhưng, sau đó bạn sẽ không thể chỉ định toán tử logic một cách động. – Igor

5

Đây là mã của tôi. Không hoàn hảo, nhưng làm việc tốt. Tôi hy vọng nó sẽ giúp ai đó:

static System.Data.DataTable DtTbl (System.Data.DataTable[] dtToJoin) 
    { 
     System.Data.DataTable dtJoined = new System.Data.DataTable(); 

     foreach (System.Data.DataColumn dc in dtToJoin[0].Columns) 
      dtJoined.Columns.Add(dc.ColumnName); 

     foreach (System.Data.DataTable dt in dtToJoin) 
      foreach (System.Data.DataRow dr1 in dt.Rows) 
      { 
       System.Data.DataRow dr = dtJoined.NewRow(); 
       foreach (System.Data.DataColumn dc in dtToJoin[0].Columns) 
        dr[dc.ColumnName] = dr1[dc.ColumnName]; 

       dtJoined.Rows.Add(dr); 
      } 

     return dtJoined; 
    } 
1

chức năng này sẽ tham gia 2 bảng với một nổi tiếng tham gia lĩnh vực, nhưng điều này không thể cho phép 2 lĩnh vực có cùng tên trên cả hai bảng trừ lĩnh vực tham gia, một thay đổi đơn giản sẽ được lưu một từ điển với một bộ đếm và chỉ thêm số vào cùng một tên filds.

public static DataTable JoinDataTable(DataTable dataTable1, DataTable dataTable2, string joinField) 
{ 
    var dt = new DataTable(); 
    var joinTable = from t1 in dataTable1.AsEnumerable() 
          join t2 in dataTable2.AsEnumerable() 
           on t1[joinField] equals t2[joinField] 
          select new { t1, t2 }; 

    foreach (DataColumn col in dataTable1.Columns) 
     dt.Columns.Add(col.ColumnName, typeof(string)); 

    dt.Columns.Remove(joinField); 

    foreach (DataColumn col in dataTable2.Columns) 
     dt.Columns.Add(col.ColumnName, typeof(string)); 

    foreach (var row in joinTable) 
    { 
     var newRow = dt.NewRow(); 
     newRow.ItemArray = row.t1.ItemArray.Union(row.t2.ItemArray).ToArray(); 
     dt.Rows.Add(newRow); 
    } 
    return dt; 
} 
Các vấn đề liên quan