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("Col1") = = ra.Field("Col1") && rb.Field("Col2") == ra.Field("Col2"))) .CopyToDataTable(); 【参考方案1】:

或者使用 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 拉到函数中?

C# 使用带有 where 子句的 Linq 查询作为 dataTable 上的变量

如何使用 linq lambda 扩展方法执行带有 where 子句的左外连接