2009-03-20 7 views
35

Soit T1 et T2 sont DataTable s avec des champs suivantsjointure de DataTables en C#

T1(CustID, ColX, ColY) 

T2(CustID, ColZ) 

J'ai besoin de la table commune

TJ (CustID, ColX, ColY, ColZ) 

Comment cela peut se faire dans le code C# de manière simple ? Merci.

Répondre

46

Si vous êtes autorisé à utiliser LINQ, consultez l'exemple suivant. Il crée deux DataTables avec des colonnes entières, les remplit avec certains enregistrements, les joint à l'aide de la requête LINQ et les affiche dans la 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

Cela a finalement fonctionné pour moi, mais j'ai passé plus d'une heure là-dessus, à l'exception de « cast spécifié non valide », remettant en question ma santé mentale, jusqu'à ce que je l'ai changé à partir (int) table1 [ « champ »] pour Convert.ToInt32 (table1 ["champ"]). – CindyH

+1

@CindyH, merci beaucoup pour votre commentaire, cela m'a fait gagner du temps. Je suppose que c'est à cause de System.Data.DataTypes, où int n'est pas inclus, mais Int32 est. Liste de tous les DataTypes ici: https://msdn.microsoft.com/en-us/library/system.data.datacolumn.datatype(v=vs.110).aspx – FrenkyB

27

Je voulais une fonction qui rejoindrait les tables sans vous obliger à définir les colonnes à l'aide d'un sélecteur de type anonyme, mais il avait du mal à trouver tout. J'ai fini par devoir faire le mien. Espérons que cela aidera tout le monde à l'avenir qui cherche ceci:

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; 
} 

Un exemple de la façon dont vous pouvez utiliser ceci:

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

Une mise en garde: Ceci est certainement pas optimisé, alors soyez attentifs lors de l'obtention aligner les comptes au-dessus de 20k. Si vous savez qu'une table sera plus grande que l'autre, essayez de placer la plus petite en premier et la plus grande en une seconde.

+0

Existe-t-il un moyen de le modifier pour pouvoir spécifier un opérateur AND ou un opérateur OR entre plusieurs conditions de «connexion»? – Igor

+0

La manière la plus simple serait de ne pas changer le code et de simplement conditionner toutes vos conditions dans une seule jointure à condition. Par exemple: 'row1.Field (" Id ") == row2.Field (" Id ") || row1.Field ("CustId") == row2.Field ("CustId") ' – Bognar

+0

Mais, vous ne pourrez pas spécifier l'opérateur logique dynamiquement. – Igor

5

Ceci est mon code. Pas parfait, mais bon travail. J'espère que cela aide quelqu'un:

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

cette fonction se joindra à 2 tables avec un connu rejoindre le terrain, mais cela ne peut pas permettre à 2 champs avec le même nom sur les deux tables, à l'exception du champ de jointure, une modification simple serait de sauver un dictionnaire avec un compteur et juste ajouter un numéro au même nom.

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; 
}