2012-11-01 64 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