2012-05-08 6 views
5

Sto cercando di unire due DataTable insieme in un modo simile a questa domanda:C# DataTable join interno con colonne dinamiche

Inner join of DataTables in C#

sto cercando di ottenere l'output di essere un unico 'combinato 'tabella, con colonne di entrambi i tavoli originali. Entrambi avranno una colonna di datestamp in comune.

La risposta fornita è valida per DataTables con colonne fisse, ma cosa succede se vengono creati dinamicamente e possono avere un numero qualsiasi di colonne, come posso unirmi a loro?

ad es.

T1 (datestamp, t1Column1, t1Column2, t1ColumnN...) 
T2 (datestamp, t2Column1, t2Column2, t2ColumnN...) 

Vorrei unirsi per creare la seguente:

J1 (datestamp, t1Column1, t1Column2, t1ColumnN, ..., t2Column1, t2Column2, t2ColumnN...) 

è possibile?

+0

Si può usare "linq"? –

+0

Puoi dare un esempio di alcuni dati che sarebbero il risultato che vuoi? –

+0

Non penso che Linq sia un'opzione in quanto è necessario conoscere i nomi delle colonne in cui si stava tentando di proiettarle. – finoutlook

risposta

7

ho trovato una soluzione che non si basa su loop attraverso le colonne.

Utilizza il metodo "Unisci", che in precedenza avevo archiviato poiché pensavo che entrambe le tabelle richiedessero la stessa struttura.

In primo luogo è necessario creare una chiave primaria su due data-tabelle:

// set primary key 
T1.PrimaryKey = new DataColumn[] { T1.Columns["DateStamp"] }; 
T2.PrimaryKey = new DataColumn[] { T2.Columns["DateStamp"] }; 

Quindi aggiungere entrambe le tabelle ad un modo un rapporto di set di dati possono essere aggiunti:

// add both data-tables to data-set 
DataSet dsContainer = new DataSet(); 
dsContainer.Tables.Add(T1); 
dsContainer.Tables.Add(T2); 

Successivo aggiungi la relazione tra le due colonne chiave nel set di dati:

// add a relationship between the two timestamp columns 
DataRelation relDateStamp = new DataRelation("Date", new DataColumn[] { T1.Columns["DateStamp"] }, new DataColumn[] { T2.Columns["DateStamp"] }); 
dsContainer.Relations.Add(relDateStamp); 

Finalmente ora è possibile copiare il primo tabella dati in una nuova versione 'combinato', e poi immettersi nella seconda:

// populate combined data 
DataTable dtCombined = new DataTable(); 
dtCombined = T1.Copy(); 
dtCombined.Merge(T2, false, MissingSchemaAction.Add); 

Nota: Il metodo di unione richiede il secondo argomento essere falso altrimenti copia la struttura, ma non i dati del secondo tavolo.

Questo sarebbe poi combinare le seguenti tabelle:

T1 (2012-05-09, 111, 222) 
T2 (2012-05-09, 333, 444, 555) 

in una versione combinata basata sul-chiave primaria:

J1 (2012-05-09, 111, 222, 333, 444, 555) 
1

Penso che sia possibile adattare la risposta nella domanda collegata per utilizzare lo index of the column, anziché il nome della colonna. O si può solo scorrere le voci in ogni riga, come questo:

foreach(DataRow row in table.Rows) 
{ 
    foreach(DataColumn column in table.Columns) 
    { 
     object value = row[column]; // add this to your combined table 
    } 
} 
+0

Grazie - Speravo di evitare il looping di tutte le colonne poiché ho già alcuni loop nidificati per configurare le tabelle originali. Questo potrebbe diventare piuttosto complesso se i dati nelle tabelle hanno molte date/chiavi diverse. – finoutlook

1

Dopo stancando di vedere tutto unire questi interno funzioni che don' t emulare in modo affidabile SQL, ho deciso di creare il mio qui:

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 esame come si può usare:

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

Ben fatto. C'è un modo per modificarlo per poter specificare un operatore AND o OR tra più condizioni di "join on"? – Igor