C#中DataTables的内连接
Posted
技术标签:
【中文标题】C#中DataTables的内连接【英文标题】:Inner join of DataTables in C# 【发布时间】:2010-10-14 12:35:53 【问题描述】:令 T1 和 T2 为 DataTable
s,具有以下字段
T1(CustID, ColX, ColY)
T2(CustID, ColZ)
我需要联表
TJ (CustID, ColX, ColY, ColZ)
如何在 C# 代码中以简单的方式完成此操作?谢谢。
【问题讨论】:
这不是DataTable.Merge
方法吗?
【参考方案1】:
我试着用下一个方法来做这个
public static DataTable JoinTwoTables(DataTable innerTable, DataTable outerTable)
DataTable resultTable = new DataTable();
var innerTableColumns = new List<string>();
foreach (DataColumn column in innerTable.Columns)
innerTableColumns.Add(column.ColumnName);
resultTable.Columns.Add(column.ColumnName);
var outerTableColumns = new List<string>();
foreach (DataColumn column in outerTable.Columns)
if (!innerTableColumns.Contains(column.ColumnName))
outerTableColumns.Add(column.ColumnName);
resultTable.Columns.Add(column.ColumnName);
for (int i = 0; i < innerTable.Rows.Count; i++)
var row = resultTable.NewRow();
innerTableColumns.ForEach(x =>
row[x] = innerTable.Rows[i][x];
);
outerTableColumns.ForEach(x =>
row[x] = outerTable.Rows[i][x];
);
resultTable.Rows.Add(row);
return resultTable;
【讨论】:
【参考方案2】:此函数将使用已知的连接字段连接 2 个表,但这不能允许两个表上除连接字段外的两个表具有相同名称的 2 个字段,一个简单的修改是保存一个带有计数器的字典,然后将数字添加到同名字段。
public static DataTable JoinDataTable(DataTable dataTable1, DataTable dataTable2, string joinField)
var dt = new DataTable();
var joinTable = from t1 in dataTable1.AsEnumerable()
join t2 in dataTable2.AsEnumerable()
on t1[joinField] equals t2[joinField]
select new t1, t2 ;
foreach (DataColumn col in dataTable1.Columns)
dt.Columns.Add(col.ColumnName, typeof(string));
dt.Columns.Remove(joinField);
foreach (DataColumn col in dataTable2.Columns)
dt.Columns.Add(col.ColumnName, typeof(string));
foreach (var row in joinTable)
var newRow = dt.NewRow();
newRow.ItemArray = row.t1.ItemArray.Union(row.t2.ItemArray).ToArray();
dt.Rows.Add(newRow);
return dt;
【讨论】:
【参考方案3】:这是我的代码。不完美,但工作良好。我希望它可以帮助某人:
static System.Data.DataTable DtTbl (System.Data.DataTable[] dtToJoin)
System.Data.DataTable dtJoined = new System.Data.DataTable();
foreach (System.Data.DataColumn dc in dtToJoin[0].Columns)
dtJoined.Columns.Add(dc.ColumnName);
foreach (System.Data.DataTable dt in dtToJoin)
foreach (System.Data.DataRow dr1 in dt.Rows)
System.Data.DataRow dr = dtJoined.NewRow();
foreach (System.Data.DataColumn dc in dtToJoin[0].Columns)
dr[dc.ColumnName] = dr1[dc.ColumnName];
dtJoined.Rows.Add(dr);
return dtJoined;
【讨论】:
【参考方案4】:我想要一个无需您使用匿名类型选择器定义列即可连接表的函数,但很难找到。我最终不得不自己做。希望这将有助于将来搜索此内容的任何人:
private DataTable JoinDataTables(DataTable t1, DataTable t2, params Func<DataRow, DataRow, bool>[] joinOn)
DataTable result = new DataTable();
foreach (DataColumn col in t1.Columns)
if (result.Columns[col.ColumnName] == null)
result.Columns.Add(col.ColumnName, col.DataType);
foreach (DataColumn col in t2.Columns)
if (result.Columns[col.ColumnName] == null)
result.Columns.Add(col.ColumnName, col.DataType);
foreach (DataRow row1 in t1.Rows)
var joinRows = t2.AsEnumerable().Where(row2 =>
foreach (var parameter in joinOn)
if (!parameter(row1, row2)) return false;
return true;
);
foreach (DataRow fromRow in joinRows)
DataRow insertRow = result.NewRow();
foreach (DataColumn col1 in t1.Columns)
insertRow[col1.ColumnName] = row1[col1.ColumnName];
foreach (DataColumn col2 in t2.Columns)
insertRow[col2.ColumnName] = fromRow[col2.ColumnName];
result.Rows.Add(insertRow);
return result;
如何使用它的示例:
var test = JoinDataTables(transactionInfo, transactionItems,
(row1, row2) =>
row1.Field<int>("TransactionID") == row2.Field<int>("TransactionID"));
一个警告:这肯定不是优化的,所以当行数超过 20k 时要小心。如果您知道一张桌子会比另一张大,请尝试将较小的放在第一个,然后将较大的放在第二个。
【讨论】:
有没有办法修改它,以便能够在多个“加入”条件之间指定 AND 或 OR 运算符? 最简单的方法是不更改代码,只需将所有条件打包到一个条件连接中。例如:row1.Field<int>("Id") == row2.Field<int>("Id") || row1.Field<string>("CustId") == row2.Field<string>("CustId")
但是,您将无法动态指定逻辑运算符。
这并不完全正确,尽管它确实变得非常丑陋:(useAnd && row1.Field<int>("Id") == row2.Field<int>("Id") && row1.Field<string>("CustId") == row2.Field<string>("CustId")) || (!useAnd && row1.Field<int>("Id") == row2.Field<int>("Id") || row1.Field<string>("CustId") == row2.Field<string>("CustId"))
真的,不过,如果你在加入谓词中有任何复杂的规则,你应该只使用一个谓词,其中所有规则都卡在那里(可能拉到它自己的函数中以使代码看起来不错) .【参考方案5】:
如果允许您使用 LINQ,请查看以下示例。它创建两个具有整数列的 DataTable,用一些记录填充它们,使用 LINQ 查询连接它们并将它们输出到控制台。
DataTable dt1 = new DataTable();
dt1.Columns.Add("CustID", typeof(int));
dt1.Columns.Add("ColX", typeof(int));
dt1.Columns.Add("ColY", typeof(int));
DataTable dt2 = new DataTable();
dt2.Columns.Add("CustID", typeof(int));
dt2.Columns.Add("ColZ", typeof(int));
for (int i = 1; i <= 5; i++)
DataRow row = dt1.NewRow();
row["CustID"] = i;
row["ColX"] = 10 + i;
row["ColY"] = 20 + i;
dt1.Rows.Add(row);
row = dt2.NewRow();
row["CustID"] = i;
row["ColZ"] = 30 + i;
dt2.Rows.Add(row);
var results = from table1 in dt1.AsEnumerable()
join table2 in dt2.AsEnumerable() on (int)table1["CustID"] equals (int)table2["CustID"]
select new
CustID = (int)table1["CustID"],
ColX = (int)table1["ColX"],
ColY = (int)table1["ColY"],
ColZ = (int)table2["ColZ"]
;
foreach (var item in results)
Console.WriteLine(String.Format("ID = 0, ColX = 1, ColY = 2, ColZ = 3", item.CustID, item.ColX, item.ColY, item.ColZ));
Console.ReadLine();
// Output:
// ID = 1, ColX = 11, ColY = 21, ColZ = 31
// ID = 2, ColX = 12, ColY = 22, ColZ = 32
// ID = 3, ColX = 13, ColY = 23, ColZ = 33
// ID = 4, ColX = 14, ColY = 24, ColZ = 34
// ID = 5, ColX = 15, ColY = 25, ColZ = 35
【讨论】:
这最终对我有用,但我花了一个多小时,除了“指定的演员表无效”,质疑我的理智,直到我把它从 (int)table1["field" ] 到 Convert.ToInt32(table1["field"]). @CindyH,非常感谢您的评论,它节省了我的时间。我猜这是因为 System.Data.DataTypes,其中不包括 int,但 Int32 是。此处列出所有数据类型:msdn.microsoft.com/en-us/library/…以上是关于C#中DataTables的内连接的主要内容,如果未能解决你的问题,请参考以下文章
使用 Angular 4 在 datatables.net 中实现自定义搜索
jquery DataTables 哪个参数是设置准确查询?不想模糊查询