简体   繁体   English

如何计算Linq左联接右侧没有匹配的记录数?

[英]How do I count the number of records with no match on the right side of a Linq left join?

I am trying to analyse a phone bill, which comprises a load of mobile numbers and associated data. 我正在尝试分析电话账单,其中包含大量的手机号码和相关数据。 Each number either belongs to somebody in the company, or is unassigned. 每个号码要么属于公司内的某个人,要么未分配。

I am using this query to match the mobile number to an employee record 我正在使用此查询将手机号码与员工记录匹配

var billInfo = from  row in csvTable.AsEnumerable()
               join d in employeeList 
               on row.Field<string>("Phone number") equals d.Mobile into t 
                from rt in t.DefaultIfEmpty()
                    select new
                     {
                       empNo = rt == null ? null : rt.EmpNo,
                       totalRows = csvTable.Rows.Count,
                       unassignedNumbers = t.Where(x => x.EmpNo == null).Count(),
                       name = row.Field<string>("User name"),
                       mobile = row.Field<string>("Phone number")
                      };

I want to get the number of unassigned numbers back in the unassignedNumbers field. 我想在unassignedNumbers字段中获取未分配号码的数量。 (ie If there are 100 rows (one per phone number) in the csvTable datatable, and 70 have an employee record matching in employeeList, I want to return 30 as the value - the number of rows with no matching employee). (即,如果csvTable数据表中有100行(每个电话号码一个),而70在雇员列表中有匹配的雇员记录,我想返回30作为值-没有匹配的雇员的行数)。

The following line: 下一行:

unassignedNumbers = t.Where(x => x.EmpNo == null).Count,

is where the problem is. 问题出在哪里。 It always evaluates to zero, rather than the number of rows with an "empty" employee number (empNo). 它始终求值为零,而不是员工人数为“空”(empNo)的行数。

Use Count() , not Count . 使用Count()而不是Count The latter is an ICollection<T> property, while you're dealing with an IEnumerable<T> . 后者是ICollection<T>属性,而您正在处理IEnumerable<T>

As for the logic of your query, you are running t.Where() on t , which is an inner join. 至于查询的逻辑,您正在t上运行t.Where() ,这是一个内部t.Where() Try 尝试

var billInfo = (from  row in csvTable.AsEnumerable()
           join d in employeeList 
           on row.Field<string>("Phone number") equals d.Mobile into t 
           from rt in t.DefaultIfEmpty()
           where rt == null
           select row.Field<string>("Phone number")).Count();

Your query is giving you at least one item for each item in your csvTable . 您的查询为您的csvTable每个项目至少提供了一个项目。 The data you want for unassignedNumbers would be exactly one value for the entire data set. 您想要的unassignedNumbers数据将是整个数据集的一个值。 So you'd have to do a completely separate query to do that and then just assign that value directly into the results of your query if desired. 因此,您必须执行一个完全独立的查询才能执行此操作,然后根据需要直接将该值直接分配给查询结果。

int allUnassignedNumbers = 
    (from  row in csvTable.AsEnumerable()
    join d in employeeList 
    on row.Field<string>("Phone number") equals d.Mobile into t 
    from rt in t.DefaultIfEmpty()
    where rt == null
    select 1).Count();

var billInfo = 
    from  row in csvTable.AsEnumerable()
    join d in employeeList 
    on row.Field<string>("Phone number") equals d.Mobile into t 
    from rt in t.DefaultIfEmpty()
    select new
    {
        empNo = rt == null ? null : rt.EmpNo,
        totalRows = csvTable.Rows.Count,
        unassignedNumbers = allUnassignedNumbers,
        name = row.Field<string>("User name"),
        mobile = row.Field<string>("Phone number")
    };

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM