2009-03-20 10 views
35

Let T1 y T2 son DataTable s con siguientes camposcombinación interna de tablas de datos en C#

T1(CustID, ColX, ColY) 

T2(CustID, ColZ) 

necesito la tabla conjunta

TJ (CustID, ColX, ColY, ColZ) 

¿Cómo se puede hacer esto en C# código de una manera sencilla ? Gracias.

Respuesta

46

Si puede usar LINQ, mire el siguiente ejemplo. Crea dos tablas de datos con columnas enteras, las rellena con algunos registros, las une mediante la consulta LINQ y las envía a la consola.

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

Esto eventualmente trabajó para mí, pero me pasé más de una hora sobre el mismo, con la excepción de "la conversión especificada no es válida", cuestionando mi cordura, hasta que me cambié de tabla1 [ "campo"] (int) a Convert.ToInt32 (tabla1 ["campo"]). – CindyH

+1

@CindyH, muchas gracias por su comentario, me ahorró tiempo. Supongo que esto se debe a System.Data.DataTypes, donde int no está incluido, pero Int32 sí lo está. Lista de todos los tipos de datos aquí: https://msdn.microsoft.com/en-us/library/system.data.datacolumn.datatype(v=vs.110).aspx – FrenkyB

27

quería una función que se uniría a las tablas sin necesidad de definir las columnas mediante un selector de tipo anónimo, pero tenía un tiempo difícil encontrar ninguna. Terminé teniendo que hacer el mío. Esperamos que esto ayudará a nadie en el futuro que busca esto:

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 ejemplo de cómo se puede utilizar la siguiente:

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

Una advertencia: Esto ciertamente no está optimizado, lo que debe tener en cuenta al conseguir para remar recuentos por encima de 20k. Si sabes que una mesa será más grande que la otra, intenta poner la más pequeña primero y la más grande por segundo.

+0

¿Hay alguna manera de modificarlo para poder especifique un AND y un operador OR entre múltiples condiciones de "join on"? – Igor

+0

La manera más fácil sería no cambiar el código y simplemente empaquetar todas sus condiciones en una sola condición. Por ejemplo: 'row1.Field (" Id ") == row2.Field (" Id ") || row1.Field ("CustId") == row2.Field ("CustId") ' – Bognar

+0

Pero, entonces no podrá especificar el operador lógico de forma dinámica. – Igor

5

Este es mi código. No es perfecto, pero funciona bien. Espero que ayude a alguien:

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

esta función se unirá a 2 mesas con un conocido campo de combinación, pero esto no puede permitir 2 campos con el mismo nombre en ambas tablas, excepto el campo de unión, una simple modificación sería ahorrar un diccionario con un contador y solo agrega un número al mismo nombre 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; 
} 
Cuestiones relacionadas