【问题标题】:Combining two tables into one将两张表合二为一
【发布时间】:2012-10-21 13:58:29
【问题描述】:

我需要将两个数据模式合并为一个。我有 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 语句查询数据集并用结果填充表。我没有完全连接到我的数据库,因为我已经在本地填充了一个数据集。

------编辑 ------ 我真的只需要一种从两个表的查询中创建数据行数组的方法。

【问题讨论】:

  • 您需要一个新的合并数据表还是匿名类型就足够了?
  • 我认为这两种方式都没有关系,只要我可以在流程结束时将表格的内容提供给报表查看器。
  • 数据库也会这样做,你可以使用UNION关键字。
  • @BaileyS:但是数据已经在内存中了。 Ccorock:用Linq-To-DataSet 连接表很容易,你用的是什么.NET 框架版本?
  • 这就是为什么我遇到这样的麻烦,因为我想使用通常在数据库上使用的 Sql 样式查询,但我不得不使用加载的数据集。

标签: sql vb.net linq dataset


【解决方案1】:

您可以在这里使用我最近为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")
            }

【讨论】:

  • 这是一部出色的作品,虽然我希望在 vb 中更简单一些。我可能最终会转换它。
  • @Ccorock:对不起 C#,我现在还没有时间将它转换为 VB 代码。编辑了我的答案以提供具有匿名类型和 Linq 的 VB.NET 方法。
  • @Ccorock:刚刚看到您使用的是 VS 2005。不幸的是,我的回答对您没有帮助。
  • 是的,我很欣赏它。
【解决方案2】:

试试这个:

  ''' <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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-03
    相关资源
    最近更新 更多