2013-05-21 7 views
5

Mam wiele tabel z danymi: chcę je połączyć (mój PK: emp_num)Jak połączyć kilka DataTables (każdy DataTable powrót jeden wiersz) w jednym rzędzie

var tblEmp_data = new DataTable();//one row 
var tblEmp_time = new DataTable();//one row 
var tbl_emp_mission = new DataTable();//one row 

tblEmp_data = GetEmpInfo(empNum); 
tblEmp_time = GetEmpTime(empNum, start_period, end_period); 
tbl_emp_mission = GetEmpMission(empNum, start_period, end_period); 

tblEmp_data.Merge(tblEmp_time, false, MissingSchemaAction.Add); 
tblEmp_data.AcceptChanges(); 
tblEmp_data.Merge(tbl_emp_mission, false, MissingSchemaAction.Add); 
tblEmp_data.AcceptChanges(); 

Teraz mogę dane w wielu wierszach zamiast w jednym wierszu! Chcę dane w jednym rzędzie? jak to zrobić ?


Uwaga: chcę wszystkie kolumny pozwalają zerowy wyjątkiem klucz podstawowy więc uniknąć tego wyjątek:

failed to enable constraints. one or more rows contain values violating non-null, unique, or foreign-key constraints 

edycja:

Trzecia tabela które powodują ten problem:

public static DataTable GetEmpMission(int empNum, DateTime start_period, DateTime end_period) 
     { 
      using (IfxConnection con = new IfxConnection(ConfigurationManager.ConnectionStrings["tl"].ToString())) 
      { 
       DataTable dt = new DataTable(); 
       StringBuilder cmdTxt = new StringBuilder(); 
       cmdTxt.Append(" SELECT COUNT(emp_num) "); 
       cmdTxt.Append(" FROM hs_mission WHERE emp_num = ? AND from_date BETWEEN ? AND ? "); 

       using (var myIfxCmd = new IfxCommand(cmdTxt.ToString(), con)) 
       { 

        myIfxCmd.CommandType = CommandType.Text; 
        if (con.State == ConnectionState.Closed) 
        { 
         con.Open(); 
        } 
        myIfxCmd.Parameters.Add("emp_num", IfxType.SmallInt); 
        myIfxCmd.Parameters.Add("start_period", IfxType.Date); 
        myIfxCmd.Parameters.Add("end_period", IfxType.Date); 

        myIfxCmd.Parameters[0].Value = ((object)empNum) ?? DBNull.Value; 
        myIfxCmd.Parameters[1].Value = ((object)start_period.Date) ?? DBNull.Value; 
        myIfxCmd.Parameters[2].Value = ((object)end_period.Date) ?? DBNull.Value; 

        using (IfxDataReader dr = myIfxCmd.ExecuteReader()) 
        { 
         dt.Load(dr); 
         dt.Columns.Add("emp_num", typeof(Int32)); 
         dt.Rows[0]["emp_num"] = empNum; 
         dt.AcceptChanges(); 
        } 

       } 
       con.Close(); 
       con.Dispose(); 
       return dt; 


      } 

     } 

dane powrócić, ale w ten sposób:

column1   emp_num 

0     6762 

i rzucać wyjątek:

failed to enable constraints. one or more rows contain values violating non-null, unique, or foreign-key constraints 
+0

masz trzy tabele można dać przykładu podoba danych we wszystkich trzech stole i format dla czwartej tabeli? podałeś tylko jeden. – Ratna

Odpowiedz

9

Więc empNum kolumna jest kluczem, który udostępnić wszystkie tabele? To brzmi tak, jakby można użyć my MergeAll:

public static DataTable MergeAll(this IList<DataTable> tables, String primaryKeyColumn) 
{ 
    if (!tables.Any()) 
     throw new ArgumentException("Tables must not be empty", "tables"); 
    if(primaryKeyColumn != null) 
     foreach(DataTable t in tables) 
      if(!t.Columns.Contains(primaryKeyColumn)) 
       throw new ArgumentException("All tables must have the specified primarykey column " + primaryKeyColumn, "primaryKeyColumn"); 

    if(tables.Count == 1) 
     return tables[0]; 

    DataTable table = new DataTable("TblUnion"); 
    table.BeginLoadData(); // Turns off notifications, index maintenance, and constraints while loading data 
    foreach (DataTable t in tables) 
    { 
     foreach (DataColumn col in t.Columns) 
      col.ReadOnly = false; // this might be required in your case 
     table.Merge(t); // same as table.Merge(t, false, MissingSchemaAction.Add); 
    } 
    table.EndLoadData(); 

    if (primaryKeyColumn != null) 
    { 
     // since we might have no real primary keys defined, the rows now might have repeating fields 
     // so now we're going to "join" these rows ... 
     var pkGroups = table.AsEnumerable() 
      .GroupBy(r => r[primaryKeyColumn]); 
     var dupGroups = pkGroups.Where(g => g.Count() > 1); 
     foreach (var grpDup in dupGroups) 
     { 
      // use first row and modify it 
      DataRow firstRow = grpDup.First(); 
      foreach (DataColumn c in table.Columns) 
      { 
       if (firstRow.IsNull(c)) 
       { 
        DataRow firstNotNullRow = grpDup.Skip(1).FirstOrDefault(r => !r.IsNull(c)); 
        if (firstNotNullRow != null) 
         firstRow[c] = firstNotNullRow[c]; 
       } 
      } 
      // remove all but first row 
      var rowsToRemove = grpDup.Skip(1); 
      foreach(DataRow rowToRemove in rowsToRemove) 
       table.Rows.Remove(rowToRemove); 
     } 
    } 

    return table; 
} 

następnie używać go w ten sposób:

var tables = new[] { tblEmp_data, tblEmp_time, tbl_emp_mission }; 
tblEmp_data = tables.MergeAll("empNum"); 
+0

Próbuję tej metody, ale zawsze uzyskać 'nie można włączyć więzi. jeden lub więcej wierszy zawiera wartości naruszające ograniczenia inne niż zerowy, unikatowe lub klucze obce " może być jedna tabela jest pusta –

+0

Czy ta metoda może przynieść całe trzy wiersze z trzech elementów danych w jednym wierszu? –

+0

@just_name: Tak, to jest cel. –

3

Jeśli dobrze rozumiem, masz dane w trzech DataTables, a każda tabela ma kolumnę (lub wiele kolumn), które chcesz mieć w tabeli wyników. Zasadniczo każda z tabel zawiera pojedynczy wiersz i chcesz scalić kolumny.

W tym przypadku ja po prostu stworzyć nową kolumnę, a następnie skopiować wartość przez:

void MergeColumns_SO16666297(DataTable destination, DataTable source, IEnumerable<string> columnsToSkip) 
{ 
if(columnsToSkip==null) columnsToSkip= new List<string>(); 
foreach(var col in source.Columns.OfType<DataColumn>().Where(col=>!columnsToSkip.Contains(col.ColumnName))) 
    { 
     var newCol = destination.Columns.Add(col.ColumnName, col.DataType); 
     newCol.AllowDBNull = true ; 
     destination.Rows[0][newCol] = source.Rows[0][col]; 
    } 
} 

Używaj go tak: MergeColumns_SO16666297(tblEmp_data,tblEmp_time,new string[]{"emp_num"});


moja druga myśl, utworzyć klasę TransferObjects , ma wszystkie potrzebne pola i kopiuje wartości z poszczególnych tabel.

2

ten powinien Ci dane w jednym rzędzie, pod warunkiem, że podstawowa kolumna klucz ma taką samą nazwę we wszystkich tabelach danych

private DataTable MergeDataTables(List<DataTable> tables) 
    { 
     //. 
     if (null == tables || false == tables.Any()) 
     { 
      return null; 
     } 

     //. 
     DataTable merged = tables.First(); 

     //. 
     for (int i = 1; i < tables.Count; i++) 
     { 
      var cur = tables[i]; 

      //.merge columns 
      foreach (DataColumn c in cur.Columns) 
      { 
       if (-1 == merged.Columns.IndexOf(c.ColumnName)) 
       { 
        merged.Columns.Add(c.ColumnName, c.DataType); 
       } 
      } 

      //.merge rows 
      foreach (DataRow r in cur.Rows) 
      { 
       merged.ImportRow(r); 
      } 
     } 

     //. 
     return merged; 
    } 
Powiązane problemy