Linq - 如何在 where 子句中使用 2 列
Posted
技术标签:
【中文标题】Linq - 如何在 where 子句中使用 2 列【英文标题】:Linq - How to use 2 columns in where clause 【发布时间】:2020-12-19 12:08:35 【问题描述】:我有两个数据表,我想从第一个表中选择第二个表中不存在的行使用 linq 基于 2 列(col1,col2)
请查看以下示例
我尝试了此页面中的示例 Compare two DataTables and select the rows that are not present in second table
从示例中它们仅使用一列
编辑 1 我试过了
DataTable Table1 = new DataTable();
Table1.Columns.Add("col1", typeof(string));
Table1.Columns.Add("col2", typeof(string));
DataRow r1 = Table1.NewRow();
r1["col1"] = "A";
r1["col2"] = "A-1";
Table1.Rows.Add(r1);
DataRow r2 = Table1.NewRow();
r2["col1"] = "B";
r2["col2"] = "B-2";
Table1.Rows.Add(r2);
DataRow r3 = Table1.NewRow();
r3["col1"] = "C";
r3["col2"] = "C-3";
Table1.Rows.Add(r3);
DataRow r4 = Table1.NewRow();
r4["col1"] = "D";
r4["col2"] = "D-4";
Table1.Rows.Add(r4);
DataRow r5 = Table1.NewRow();
r5["col1"] = "E";
r5["col2"] = "E-5";
Table1.Rows.Add(r5);
DataTable Table2 = new DataTable();
Table2.Columns.Add("col1", typeof(string));
Table2.Columns.Add("col2", typeof(string));
DataRow r11 = Table2.NewRow();
r11["col1"] = "A";
r11["col2"] = "A-1";
Table2.Rows.Add(r11);
DataRow r22 = Table2.NewRow();
r22["col1"] = "B";
r22["col2"] = "B-2";
Table2.Rows.Add(r22);
DataRow r33 = Table2.NewRow();
r33["col1"] = "C";
r33["col2"] = "C-4";
Table2.Rows.Add(r33);
DataRow r44 = Table2.NewRow();
r44["col1"] = "D";
r44["col2"] = "DD";
Table2.Rows.Add(r44);
DataRow r55 = Table2.NewRow();
r55["col1"] = "E";
r55["col2"] = "EE";
Table2.Rows.Add(r55);
DataRow r66 = Table2.NewRow();
r66["col1"] = "F";
r66["col2"] = "FF";
Table2.Rows.Add(r66);
示例 - 1
DataTable table3s = (from a in Table1.AsEnumerable()
where !Table2.AsEnumerable().Any(e => (e.Field<string>("col1") == a.Field<string>("col1"))
&& (e.Field<string>("col2") == a.Field<string>("col2")))
select a).CopyToDataTable();
示例 - 2
DataTable TableC = Table1.AsEnumerable().Where(ra => !Table2.AsEnumerable()
.Any(rb => rb.Field<string>("col1") == ra.Field<string>("col1")
&& rb.Field<string>("col2") == ra.Field<string>("col2"))).CopyToDataTable();
示例 1 和 2 在没有匹配行时会出错
源不包含 DataRows
请根据我的示例代码给出工作示例并建议最有效的方法,因为 DataTable 可能包含大记录,如 10000 行、20000 行等
【问题讨论】:
使用下面的代码:DataTable TableC = table1.AsEnumerable() .Where(ra => !table2.AsEnumerable() .Any(rb => rb.Field或者使用 Any 有一个适当的外连接而没有隐式循环的东西:
var res = from a in Table1
join b in Table2
on (a.col1, a.col2) equals (b.col1, b.col2)
into temp
from b in temp.DefaultIfEmpty(default)
where b.col2 == null
select a;
它只是使用复合键连接两个表并将其放入临时表中。然后它执行外部联接 (DefaultIfEmpty
) 并仅从 Table1 中获取联接返回空结果的条目。
【讨论】:
根据我的问题 Edit1 中的示例给出示例代码【参考方案2】:假设你有
class Table1
public string col1 get; set;
public string col2 get; set;
class Table2
public string col1 get; set;
public string col2 get; set;
和
List<Table1> table1s = new List<Table1>();
List<Table2> table2s = new List<Table2>();
查询是
var table3s = from table1 in table1s
where !table2s.Any(e => (e.col1 == table1.col1) && (e.col2 == table1.col2))
select table1;
【讨论】:
【参考方案3】:试试这个。基本上,这行代码从 Table1 中选择 Table2 中不存在“col1”和“col2”值的每个元素。
var results = Table1.AsEnumerable().Where(t1 => Table2.AsEnumerable().All(t2 => t2["col1"] !=
t1["col1"] || t2["col2"] != t1["col2"]));
【讨论】:
【参考方案4】:我尝试使用以下逻辑解决此问题。如果我在这里遗漏了什么,请告诉我?
static void LinkPerf()
string[] arr = "A", "B", "C", "D", "E", "F", "G", "H", "I" ;
DataTable table1 = new DataTable();
table1.Columns.Add("Id");
table1.Columns.Add("Col1");
table1.Columns.Add("Col2");
DataTable table2 = new DataTable();
table2.Columns.Add("Id");
table2.Columns.Add("Col1");
table2.Columns.Add("Col2");
DataTable ResultTable3 = new DataTable();
ResultTable3.Columns.Add("Id");
ResultTable3.Columns.Add("Col1");
ResultTable3.Columns.Add("Col2");
Random rand = new Random();
for (int i = 1; i <= 10000; i++)
DataRow row = table1.NewRow();
int index = rand.Next(arr.Length);
var colVal = arr[index];
//Table 1
row[0] = i.ToString();
row[1] = colVal;
row[2] = colVal + "-" + i.ToString();
table1.Rows.Add(row);
//Table 2
row = table2.NewRow();
row[0] = i.ToString();
row[1] = colVal;
row[2] = (i % 5 == 0) ? colVal + colVal + i.ToString() : colVal + "-" + i.ToString();
table2.Rows.Add(row);
Stopwatch watch = new Stopwatch();
watch.Start();
var result = table1.AsEnumerable()
.Where(ra => !table2.AsEnumerable()
.Any(rb => rb.Field<string>("Col1") == ra.Field<string>("Col1") && rb.Field<string>("Col2") == ra.Field<string>("Col2")));
if (result.Any())
foreach (var item in result)
ResultTable3.ImportRow(item);
watch.Stop();
var timeTaken = watch.Elapsed;
Console.WriteLine("Time taken: " + timeTaken.ToString(@"m\:ss\.fff"));
Console.ReadLine();
【讨论】:
以上是关于Linq - 如何在 where 子句中使用 2 列的主要内容,如果未能解决你的问题,请参考以下文章
如何在 LINQ where 子句中传递 func 表达式?
Linq to Entities 中的动态 where 子句 (OR)
LINQ to SQL查询中的C#Dynamic WHERE子句
如何将重复的 where 子句表达式从 linq 拉到函数中?