2012-11-01 62 views
0

我需要將兩個數據模式合併爲一個。我有Schema1和Schema2。我需要將這兩個參與到Schema3中。此外,我有一個查詢數據集的Select語句,但我無法弄清楚如何在包含兩個表(Schema1和Schema2)的數據集上使用select語句並將它們組合到新的表schema3中,該表是一個表在由兩個表格字段組成的相同數據集中。將兩個表合併爲一個

模式1 ID, 食品, 圖書, 水稻, 洞

模式2 ID, 地毯, 字符串, 運行

模式3 ID, 食品, 書, 水稻, 洞, 地毯, 字符串, 運行

使用此命令填充Schema3表

SQL命令:

Select * Schema1 [except ID] and all fields from Schema2 [exceptID] Inner Join 
Schema2 ON Schema1.ID = Schema2.ID 
Where ID = {dynamically defined variable 'X'} 

請原諒缺乏正確的語法。這裏的主要問題是使用select語句查詢數據集,並填寫結果表。我沒有完全連接到我的數據庫,因爲我已經在本地填充了一個數據集。

------編輯------ 我真的只需要一種方法來從兩個表的查詢中創建一個數據行的數組。

+0

你需要一個新的合併DataTable嗎?或者一個匿名類型是否足夠? –

+0

只要我可以在表格的內容提供給報表查看器的過程結束時,我不會發現這兩種方式都無關緊要。 – Ccorock

+0

數據庫也會這樣做,你可以使用UNION關鍵字。 –

回答

2

你可以在這裏使用這個擴展方法,我最近從零開始編寫了another question。它可以通過一個公共密鑰合併多個表。如果沒有密鑰被指定它將只使用默認DataTable.Merge方法:

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

你可以把它用這種方式:

var tables= new[] { Schema1, Schema2}; 
DataTable Schema3 = tables.MergeAll("ID"); 

編輯:如果你不需要一個新的DataTable與你也可以使用Linq-To-DataSet(現VB.NET)合併模式:

Dim schema3 = From r1 In schema1 
      Join r2 In schema2 On r1.Field(Of Int32)("ID") Equals r2.Field(Of Int32)("ID") 
      Select New With { 
       .ID = r1.Field(Of Int32)("ID"), 
       .Food = r1.Field(Of String)("Food"), 
       .Book = r1.Field(Of String)("Book"), 
       .Rice = r1.Field(Of String)("Rice"), 
       .Cave = r1.Field(Of String)("Cave"), 
       .Carpet = r2.Field(Of String)("Carpet"), 
       .Strings = r2.Field(Of String)("Strings"), 
       .Run = r2.Field(Of String)("Run") 
      } 
+0

這是一個很好的工作,雖然我希望有一些更簡單的工作,並在vb。我最終可能會將其轉換。 – Ccorock

+0

@Ccorock:對於C#抱歉,我現在沒有時間把它轉換成VB代碼。編輯我的答案,提供一個匿名類型和Linq的VB.NET方法。 –

+0

@Ccorock:只是看到你正在使用VS 2005.然後不幸的是我的回答對你沒有幫助。 –

0

試試這個:

''' <summary> 
    ''' Merge two datatables that have a 1:1 relationship 
    ''' </summary> 
    ''' <param name="dtb1">Required Datatable.</param> 
    ''' <param name="dtb2">Required Datatable.</param> 
    ''' <param name="dtb1MatchField">Required String. Field name in dtb1 to use to match records</param> 
    ''' <param name="dtb2MatchField">Required String. Field name in dtb2 to use to match records</param> 
    ''' <remarks></remarks>' 
    Private Function MergeDataTables(ByVal dtb1 As DataTable, ByVal dtb2 As DataTable, ByVal dtb1MatchField As String, ByVal dtb2MatchField As String) As DataTable 
    Dim dtbOutput As DataTable = dtb1.Copy 
    Dim lstSkipFields As New List(Of String) 
    For Each dcl As DataColumn In dtb2.Columns 
     Try 
     dtbOutput.Columns.Add(dcl.ColumnName, dcl.DataType) 
     Catch ex As DuplicateNameException 
     lstSkipFields.Add(dcl.ColumnName) 
     End Try 
    Next dcl 
    'Merge dtb2 records that match existing records in dtb1' 
    Dim dtb2Temp As DataTable = dtb2.Copy 
    For int2 As Integer = dtb2Temp.Rows.Count - 1 To 0 Step -1 
     Dim drw2 As DataRow = dtb2Temp.Rows(int2) 
     Dim o2 As Object = drw2(dtb2MatchField) 
     For Each drw1 As DataRow In dtbOutput.Rows 
     Dim o1 As Object = drw1(dtb1MatchField) 
     If o1.ToString = o2.ToString Then 
      For Each dcl As DataColumn In dtb2Temp.Columns 
      If Not lstSkipFields.Contains(dcl.ColumnName) Then 
       drw1(dcl.ColumnName) = drw2(dcl.ColumnName) 
      End If 
      Next dcl 
      dtb2Temp.Rows.Remove(drw2) 
     End If 
     Next drw1 
    Next int2 
    'add rows that weren not in dtb1' 
    For Each drw2 As DataRow In dtb2Temp.Rows 
     Dim drw1 As DataRow = dtbOutput.NewRow 
     For Each dcl As DataColumn In dtb2Temp.Columns 
     drw1(dcl.ColumnName) = drw2(dcl.ColumnName) 
     Next dcl 
     dtbOutput.Rows.Add(drw1) 
    Next drw2 
    Return dtbOutput 
    End Function