LINQ LEFT JOIN不处理NULL值

时间:2015-01-09 10:59:45

标签: c# linq

我有两个表学生标记

学生包含以下字段:  StudentIDNameMarkID(Nullable)标记包含以下字段: MarkIDMark

  

学生表

StudentID   Name    MarkID

1           Mark    1 

2           Mike    NULL

3           John    NULL

4           Paul    2
  

标记表

MarkID  Mark

1       80

2       100

我只使用左连接方式markpaul记录。 我想要左表中的所有记录(Student) 我的查询是:

 var query=(from s in Students  join m in Marks on s.MarkID equals m.MarkID into mar
from subMark in mar.DefaultIfEmpty()
Select s.Name).ToList() 

注意:这只是一个示例  如果包含NULL值的Left表示当时左连接没有带来该记录,则使用左连接连接两个表。 请帮助我。

5 个答案:

答案 0 :(得分:4)

NULL比较始终 false。这就是SQL的三值逻辑的工作方式。如果要匹配值均为null的行,则应使用将它们都检查为null的语句。

在SQL语句中,您可以写:

ON S.MARKID=M.MARKID OR (S.MARKID IS NULL AND M.MARKID IS NULL)

在C#中,您可以使用比较运算符,LINQ提供程序会将其转换为IS NULL,例如:

on s.MarkID == m.MarkID || (s.MarkID == null && m.MarkID==null)

答案 1 :(得分:2)

/编辑:我的第一个答案是使用FULL OUTER JOIN。这是超越顶部的方式,可能是错误的,或者不是完全正确的。

新答案使用LEFT OUTER JOIN。我使用LinqPad创建了一些示例数据,以获得一个工作示例。如果您不使用LinqPad,请忽略.Dump()方法。

var Students = new List<Student>() {
        new Student() {StudentId = 1, Name ="John", MarkId = 1},
        new Student() {StudentId = 1, Name ="Paul", MarkId = 1},
        new Student() {StudentId = 1, Name ="Steve", MarkId = 1},
        new Student() {StudentId = 1, Name ="John", MarkId = 2},
        new Student() {StudentId = 1, Name ="Paul", MarkId = 3},
        new Student() {StudentId = 1, Name ="Steve", MarkId = 1},
        new Student() {StudentId = 1, Name ="Paul", MarkId = 3},
        new Student() {StudentId = 1, Name ="John"  },
        new Student() {StudentId = 1, Name ="Steve"  },
        new Student() {StudentId = 1, Name ="John", MarkId = 1}

    };

    var Marks = new List<Mark>() {
        new Mark() {MarkId = 1, Value = 60},
        new Mark() {MarkId = 2, Value = 80},
        new Mark() {MarkId = 3, Value = 100}
    };

    var StudentMarks = Students
                        .GroupJoin(
                            Marks,
                            st => st.MarkId,
                            mk => mk.MarkId,
                            (x,y) => new {
                                            StudentId = x.StudentId, 
                                            Name = x.Name,
                                            Mark = y.Select (z => z.Value).SingleOrDefault()
                                          }
                        )
                        .Dump();


}

public class Student
{
    public int StudentId { get; set; }
    public string Name { get; set; }
    public int MarkId { get; set; }
}

public class Mark
{
    public int MarkId { get; set; }
    public int Value { get; set; }
}

输出:

enter image description here

正如你在我的学生名单中看到的那样,有一个没有MarkId的2名学生。这些2获得由.SingleOrDefault()分配的默认值。我认为这将解决您的问题,并为您提供进一步填补的良好基础。

的引用: How do you perform a left outer join using linq extension methods

答案 2 :(得分:2)

问题是我们在Left join中使用where子句。因此它将丢弃空值记录。

var sampleQuery= (from f in food 
            join j in juice on f.ID equals j.ID into juiceDetails from juice in juiceDetails.DefaultIfEmpty()
            where(!j.deleted)
            join fr in fruit on f.ID equals fr.ID into fruitDetails from fruit in fruitDetails.DefaultIfEmpty()
            where(!fr.deleted)
            select new
            {
            // codes

            });

而不是这个,我们必须检查表本身的where子句。就像这个

var sampleQuery= (from f in food 
            join j in juice.Table().where(x=>!x.deleted) on f.ID equals j.ID into juiceDetails from juice in juiceDetails.DefaultIfEmpty()              
            join fr in fruit.Table().where(x=>!x.deleted) on f.ID equals fr.ID into fruitDetails from fruit in fruitDetails.DefaultIfEmpty()                
            select new
            {
            // codes

            });

它会正常工作。 谢谢。

答案 3 :(得分:1)

在您的查询中,您在加入时在Join语句中编写了From。 相反,您应该使用in ::

   from s in Students  
    join m in Marks on s.MarkID equals m.ID into mar
    from subMark in mar.DefaultIfEmpty()
    Select s.Name).ToList() 

答案 4 :(得分:0)

我有同样的问题。仅当subMark中至少有一行时,此解决方案才有效。行的ID无关紧要。

var query = (from s in Students  
               join m in Marks on s.MarkID equals m.MarkID into fullM
               into mar from subMark in mar.DefaultIfEmpty()
               where(m.Mark > 80)
               Select s.Name)
               .ToList() 

将关键字 into 变成魔术。添加该行会显示所有行以及3月中具有NULL值的行。