【问题标题】:Combining n DataTables into a Single DataTable将 n 个 DataTable 组合成一个 DataTable
【发布时间】:2012-08-30 00:39:56
【问题描述】:

所有,对此有一些问题,但我似乎无法提取足够的信息来解决我的问题。我将未知数量的表提取到 SQL Server 'Tab1'、'Tab2'、'Tab3'、...、'TabN' 中。这些表中的列不同,但行定义相同。我需要将服务器中的所有数据拉入 N 个DataTables,然后将它们组合成一个DataTable。我现在做的是

int nTmpVolTabIdx = 1;
strSqlTmp = String.Empty;
using (DataTable dataTableALL = new DataTable())
{
    while (true)
    {
        string strTmpVolName = String.Format("Tab{0}", nTmpVolTabIdx);
        strSqlTmp = String.Format("SELECT * FROM [{0}];", strTmpVolName);

        // Pull the data from 'VolX' into a local DataTable.
        using (DataTable dataTable = UtilsDB.DTFromDB(conn, strTmpVolName, strSqlTmp, false))
        {
            if (dataTable == null)
                break;
            else
                dataTableALL.Merge(dataTable);
        }
        nTmpVolTabIdx++;
    }
    ...
}

这会合并DataTables,但它们未对齐(将空白单元格填充到附加的数据集上)。我可以通过循环附加新的DataTable 的列; 但是有没有更简单/更好的方法来做到这一点(也许使用 LINQ)?

感谢您的宝贵时间。

编辑。提供示例数据集。

我需要的是

各个表是

在第一次合并操作之后,我有以下内容

再次感谢。

【问题讨论】:

  • 你说的这些表中的列不同,但行定义相同是什么意思?
  • “这些表中的列不同,但行定义相同”。你能举个例子吗?
  • 也许你正在寻找DataTable.Union
  • @TimSchmelter Dispose 方法在 DataTable 上可用。在 using 语句完成后,(当然)调用 DataTable 上的 Dispose 方法。此方法在 DataTable 的基类上实现:MarshalValueByComponent。调用 Dispose 时,会释放来自 MarshalValueByComponent(DataTable 的基类)的本机资源。因此,在与 DataTables 一起使用时,using 语句可能会缓解一些资源使用问题。此外, using 为这部分代码提供了范围...
  • 资源作为每个其他(托管)对象释放:当垃圾收集器决定这样做时,因为他需要回收 RAM,标记所有当前可访问的指针并删除所有无法访问并因此超出范围的指针。

标签: c# datatable


【解决方案1】:

该表在Merge 之后具有重复的主键,因为没有定义主键。所以要么指定PK,要么在这里尝试我从头开始编写的这个方法(所以它没有真正经过测试)

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[] { tblA, tblB, tblC };
DataTable TblUnion = tables.MergeAll("c1");

使用了这个样本数据:

var tblA = new DataTable();
tblA.Columns.Add("c1", typeof(int));
tblA.Columns.Add("c2", typeof(int));
tblA.Columns.Add("c3", typeof(string));
tblA.Columns.Add("c4", typeof(char));

var tblB = new DataTable();
tblB.Columns.Add("c1", typeof(int));
tblB.Columns.Add("c5", typeof(int));
tblB.Columns.Add("c6", typeof(string));
tblB.Columns.Add("c7", typeof(char));

var tblC = new DataTable();
tblC.Columns.Add("c1", typeof(int));
tblC.Columns.Add("c8", typeof(int));
tblC.Columns.Add("c9", typeof(string));
tblC.Columns.Add("c10", typeof(char));

tblA.Rows.Add(1, 8500, "abc", 'A');
tblA.Rows.Add(2, 950, "cde", 'B');
tblA.Rows.Add(3, 150, "efg", 'C');
tblA.Rows.Add(4, 850, "ghi", 'D');
tblA.Rows.Add(5, 50, "ijk", 'E');

tblB.Rows.Add(1, 7500, "klm", 'F');
tblB.Rows.Add(2, 900, "mno", 'G');
tblB.Rows.Add(3, 150, "opq", 'H');
tblB.Rows.Add(4, 850, "qrs", 'I');
tblB.Rows.Add(5, 50, "stu", 'J');

tblC.Rows.Add(1, 7500, "uvw", 'K');
tblC.Rows.Add(2, 900, "wxy", 'L');
tblC.Rows.Add(3, 150, "yza", 'M');
tblC.Rows.Add(4, 850, "ABC", 'N');
tblC.Rows.Add(5, 50, "CDE", 'O');

DataTable.MergeMergeAll 之后:

经过一些修改以加入MergeAll中的行:


更新

由于这个问题出现在其中一个 cmets 中,如果两个表之间的唯一关系是表中 DataRow 的索引,并且您想根据索引合并两个表:

public static DataTable MergeTablesByIndex(DataTable t1, DataTable t2)
{
    if (t1 == null || t2 == null) throw new ArgumentNullException("t1 or t2", "Both tables must not be null");

    DataTable t3 = t1.Clone();  // first add columns from table1
    foreach (DataColumn col in t2.Columns)
    {
        string newColumnName = col.ColumnName;
        int colNum = 1;
        while (t3.Columns.Contains(newColumnName))
        {
            newColumnName = string.Format("{0}_{1}", col.ColumnName, ++colNum);
        }
        t3.Columns.Add(newColumnName, col.DataType);
    }
    var mergedRows = t1.AsEnumerable().Zip(t2.AsEnumerable(),
        (r1, r2) => r1.ItemArray.Concat(r2.ItemArray).ToArray());
    foreach (object[] rowFields in mergedRows)
        t3.Rows.Add(rowFields);

    return t3;
}

示例:

var dt1 = new DataTable();
dt1.Columns.Add("ID", typeof(int));
dt1.Columns.Add("Name", typeof(string));
dt1.Rows.Add(1, "Jon");
var dt2 = new DataTable();
dt2.Columns.Add("Country", typeof(string));
dt2.Rows.Add("US");

var dtMerged = MergeTablesByIndex(dt1, dt2);

结果表包含三列 ID,Name,Country 和一行:1 Jon US

【讨论】:

  • 我在这个网站上收到的最佳答案。最后,我将 DataTables 写入 DataSet 并将其迭代到我的可视化容器中。但这要好得多 - 非常感谢您抽出宝贵的时间......一切顺利。
  • 我当然会!只需将其添加到代码库中即可。我已经对其进行了测试,并且效果很好。再次感谢...
  • 如何在 LINQ 中使用 SUM fn 聚合基于整数的列?就我而言,所有不同数据表的列集都是相同的。请提出建议。
  • @Karan:如果您有任何问题,请提出问题并提供所有必要信息以使用您的示例数据重现问题。然后,您可以在此处发布该问题的链接,以便我可以提供帮助。
  • @蒂姆。我在这里发布了我的 qstn stackoverflow.com/questions/23537162/…
猜你喜欢
  • 2012-07-24
  • 2015-12-08
  • 1970-01-01
  • 2016-04-27
  • 2011-06-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多