问题描述
所有这一切都有一些问题,但我似乎无法提取足够的信息来解决我的问题。我将未知数量的表提取到SQL Server'Tab1','Tab2','Tab3',...,'TabN'中。这些表中的列不同,但行定义相同。我需要将服务器中的所有数据从N DataTable
中拉出,然后将它们组合成一个单独的 DataTable
。我现在做的是 int nTmpVolTabIdx = 1;
strSqlTmp = String.Empty;
使用(DataTable dataTableALL = new DataTable())
{
while(true)
{
string strTmpVolName = String.Format(Tab {0}, nTmpVolTabIdx);
strSqlTmp = String.Format(SELECT * FROM [{0}];,strTmpVolName);
//将数据从VolX拉入本地DataTable。
using(DataTable dataTable = UtilsDB.DTFromDB(conn,strTmpVolName,strSqlTmp,false))
{
if(dataTable == null)
break;
else
dataTableALL.Merge(dataTable);
}
nTmpVolTabIdx ++;
}
...
}
code> DataTable ,但它们是错误对齐的(将空白单元填充到附加的数据集上)。我可以通过循环附加新的 DataTable
的列;
感谢您的时间。
编辑。要提供示例数据集。
我需要的是
个人表格
第一次合并操作后,我有以下
再次感谢
表格在合并
之后具有重复的主键,因为没有主键定义所以要么指定PK或尝试这个方法,我从头开始写了:
public static DataTable MergeAll(此IList< DataTable>表,String primaryKeyColumn)
{
if(!tables.Any())
throw new ArgumentException(Tables must不是空的,表);
if(primaryKeyColumn!= null)
foreach(表中的DataTable t)
if(!t.Columns.Contains(primaryKeyColumn))
throw new ArgumentException(所有表必须具有指定的主键列+ primaryKeyColumn,primaryKeyColumn);
if(tables.Count == 1)
返回表[0];
DataTable table = new DataTable(TblUnion);
table.BeginLoadData(); //加载数据时关闭通知,索引维护和约束
foreach(表中的DataTable t)
{
table.Merge(t); //与table.Merge(t,false,MissingSchemaAction.Add)相同;
}
table.EndLoadData();
if(primaryKeyColumn!= null)
{
//因为我们可能没有定义真正的主键,所以行现在可能会有重复的字段
// so现在我们要加入这些行...
var pkGroups = table.AsEnumerable()
.GroupBy(r => r [primaryKeyColumn]);
var dupGroups = pkGroups.Where(g => g.Count()> 1);
foreach(var grpDup in dupGroups)
{
//使用第一行并修改它
DataRow firstRow = grpDup.First();
foreach(table.Columns中的DataColumn c)
{
if(firstRow.IsNull(c))
{
DataRow firstNotNullRow = grpDup.Skip(1)。 FirstOrDefault(r =>!r.IsNull(c));
if(firstNotNullRow!= null)
firstRow [c] = firstNotNullRow [c];
}
}
//除去第一行
var rowsToRemove = grpDup.Skip(1);
foreach(DataRow rowToRemove in rowsToRemove)
table.Rows.Remove(rowToRemove);
}
}
返回表;
}
您可以这样调用:
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.Merge
$ c> MergeAll :
在 MergeAll
中的行进行了一些修改后:
更新
由于这个问题出现在其中一个意见中,如果两个表之间的唯一关系是表中的 DataRow
的索引,并且您要根据索引合并两个表:
public static DataTable MergeTablesByIndex(DataTable t1,DataTable t2)
{
if(t1 == null || t2 == null)throw new ArgumentNullException(t1或t2 两个表不能为空);
DataTable t3 = t1.Clone(); //从table1中添加列
foreach(t2.Columns中的DataColumn col)
{
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
姓名
,国家
和一行: 1 Jon US
All, there are some question on this, but I can't seem to extract enough information to solve the problem for my case. I extract an unknown number of tables into SQL Server 'Tab1', 'Tab2', 'Tab3', ... , 'TabN'. The columns in these tables are different, but the row definitions are the same. I need to pull all the data in from the Server into N DataTable
s and then combine these to form a single DataTable
. What I do currently is
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++;
}
...
}
This merges the DataTable
s but they are miss-aligned (padding blank cells onto the appended data set). I could append the columns of the new DataTable
via a loop; but is there an easier/nicer way to do this (perhaps using LINQ)?
Thanks for your time.
Edit. To provide the example data sets.
What I required is
The individual tables are
After the first Merge operation I have the following
Thanks again.
The table has repeating primary keys after the Merge
because no primary-key was defined. So either specify the PK or try this method here which i've written from scratch:
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;
}
You can call it in this way:
var tables = new[] { tblA, tblB, tblC };
DataTable TblUnion = tables.MergeAll("c1");
Used this sample data:
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');
After DataTable.Merge
in MergeAll
:
After some modifications to join the rows in MergeAll
:
Update
Since this question arose in one of the comments, if the only relation between two tables is the index of a DataRow
in the table and you want to merge both tables according to the index:
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;
}
Sample:
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);
The result table contains three columns ID
,Name
,Country
and a single row: 1 Jon US
这篇关于将n个DataTable组合到一个DataTable中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!