• 数据库和linq中的 join(连接)操作


    sql中的连接

    sql中的表连接有inner join,left join(left outer join),right join(right outer join),full join(full outer join),cross join

    在此基础上我们能扩展出 left excluding join,right excluding join,full outer excluding join

    注:left join是left outer join 的简写,即左连接和左外连接是一样的

    首先定义两个比较经典的表

    学生信息表和选课表

    student

    studentId	name	    sex
    1         	小明        	男
    2         	小黄        	男
    3         	小红        	女
    4         	小杨        	男
    

    course

    studentId	courseName
    1         	数学        
    1         	语文        
    1         	英语        
    2         	数学        
    2         	语文        
    2         	英语        
    3         	数学        
    3         	语文        
    3         	英语        
    5         	数学        
    5         	语文        
    5         	英语        
    

    这两张表其实并不规范,course的studentId其实是一个外键,对应student的studentId,所以course的studentId不应该有5,不过为了测试方便,暂且这么写

    内连接(inner join)

    select s.* ,c.courseName
    from student s
    inner join course c 
    on s.studentId=c.studentId
    

    结果

    studentId	name	     sex	courseName
    1         	小明        	男	数学        
    1         	小明        	男	语文        
    1         	小明        	男	英语        
    2         	小黄        	男	数学        
    2         	小黄        	男	语文        
    2         	小黄        	男	英语        
    3         	小红        	女	数学        
    3         	小红        	女	语文        
    3         	小红        	女	英语        
    

    左连接(left join)  

    select s.* ,c.courseName
    from student s
    left join course c 
    on s.studentId=c.studentId
    

    结果

    studentId	name	        sex	courseName
    1         	小明        	男	数学        
    1         	小明        	男	语文        
    1         	小明        	男	英语        
    2         	小黄        	男	数学        
    2         	小黄        	男	语文        
    2         	小黄        	男	英语        
    3         	小红        	女	数学        
    3         	小红        	女	语文        
    3         	小红        	女	英语        
    4         	小杨        	男	NULL
    

    右连接

    select s.* ,c.courseName
    from student s
    right join course c 
    on s.studentId=c.studentId
    

    结果

    studentId    name         sex     courseName
    1             小明            男      数学        
    1             小明            男      语文        
    1             小明            男      英语        
    2             小黄            男      数学        
    2             小黄            男      语文        
    2             小黄            男      英语        
    3             小红            女      数学        
    3             小红            女      语文        
    3             小红            女      英语        
    NULL       NULL         NULL     数学        
    NULL       NULL        NULL     语文        
    NULL       NULL         NULL     英语        

    全连接

    select s.* ,c.courseName
    from student s
    full join course c 
    on s.studentId=c.studentId
    

    结果

    studentId    name         sex   courseName
    1             小明            男    数学        
    1             小明            男    语文        
    1             小明            男    英语        
    2             小黄            男    数学        
    2             小黄            男    语文        
    2             小黄            男    英语        
    3             小红            女    数学        
    3             小红            女    语文        
    3             小红            女    英语        
    4             小杨            男    NULL
    NULL        NULL        NULL  数学        
    NULL        NULL        NULL  语文        
    NULL        NULL        NULL  英语        

    左不包含连接(left excluding join)

    select s.* ,c.courseName 
    from student s
    left join course c 
    on s.studentId=c.studentId
    where c.studentId is null

    结果

    studentId	name	sex	courseName
    4         	小杨     男	NULL
    

    右不包含连接(right excluding join)

    select s.* ,c.courseName 
    from student s
    right join course c 
    on s.studentId=c.studentId
    where s.studentId is null
    

    结果

    studentId	name	sex	courseName
    NULL	     NULL	NULL	数学        
    NULL	     NULL	NULL	语文        
    NULL	     NULL	NULL	英语        
    

    全不包含连接(Full outer excluding join)

    select s.* ,c.courseName 
    from student s
    full join course c 
    on s.studentId=c.studentId
    where s.studentId is null or c.studentId is null
    

    结果

    studentId	name	sex	courseName
    4         	小杨     男	NULL
    NULL	     NULL	NULL	数学        
    NULL	     NULL	NULL	语文        
    NULL	     NULL	NULL	英语        
    

    笛卡儿积(cross join) 

    select s.* ,c.courseName 
    from student s
    cross join course c 

    结果

    studentId    name    sex    courseName
    1             小明            男    数学        
    1             小明            男    语文        
    1             小明            男    英语        
    1             小明            男    数学        
    1             小明            男    语文        
    1             小明            男    英语        
    1             小明            男    数学        
    1             小明            男    语文        
    1             小明            男    英语        
    1             小明            男    数学        
    1             小明            男    语文        
    1             小明            男    英语        
    2             小黄            男    数学        
    2             小黄            男    语文        
    2             小黄            男    英语        
    2             小黄            男    数学        
    2             小黄            男    语文        
    2             小黄            男    英语        
    2             小黄            男    数学        
    2             小黄            男    语文        
    2             小黄            男    英语        
    2             小黄            男    数学        
    2             小黄            男    语文        
    2             小黄            男    英语        
    3             小红            女    数学        
    3             小红            女    语文        
    3             小红            女    英语        
    3             小红            女    数学        
    3             小红            女    语文        
    3             小红            女    英语        
    3             小红            女    数学        
    3             小红            女    语文        
    3             小红            女    英语        
    3             小红            女    数学        
    3             小红            女    语文        
    3             小红            女    英语        
    4             小杨            男    数学        
    4             小杨            男    语文        
    4             小杨            男    英语        
    4             小杨            男    数学        
    4             小杨            男    语文        
    4             小杨            男    英语        
    4             小杨            男    数学        
    4             小杨            男    语文        
    4             小杨            男    英语        
    4             小杨            男    数学        
    4             小杨            男    语文        
    4             小杨            男    英语        
    View Code

    两个个经典sql问题的解法

    一、取出没有选课的学生的信息

    方法一:利用left excluding join

    select s.* 
    from student s
    left join course c 
    on s.studentId=c.studentId
    where c.studentId is null
    

    结果

    studentId	name	sex
    4         	小杨     男
    

    方法二:利用exists

    思路:先找到有选课的学生的信息然后通过exists或not exists来取出想要的数据

    select * from student st 
    where not exists(
    	select s.* ,c.courseName
    	from student s
    	inner join course c 
    	on s.studentId=c.studentId
    	where st.studentId=s.studentId
    )
    

    结果跟方法一的一样

    二、取出有选课的学生的信息

    select * from student st 
    where exists(
    	select s.* ,c.courseName
    	from student s
    	inner join course c 
    	on s.studentId=c.studentId
    	where st.studentId=s.studentId
    )
    

    结果

    studentId	name	     sex
    1         	小明        	男
    2         	小黄        	男
    3         	小红        	女
    

    Linq 中的连接

    在linq中同样能实现上述sql的连接操作

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Data;
    namespace LinqJoinTest
    {
        class Program
        {
            static void Main(string[] args)
            {
                DataTable student = GetStudent();
                DataTable course = GetCourse();
                Console.WriteLine("内连接");
                IEnumerable<ResultModel> result = InnerJoin(student, course);
                foreach(ResultModel item in result)
                {
                    Console.WriteLine(string.Format("{0},{1},{2},{3}", item.id, item.name, item.sex, item.course));
                }
                Console.WriteLine("左连接");
                result = LeftJoin(student, course);
                foreach (ResultModel item in result)
                {
                    Console.WriteLine(string.Format("{0},{1},{2},{3}", item.id, item.name, item.sex, item.course));
                }
                Console.WriteLine("右连接");
                result = RightJoin(student, course);
                foreach (ResultModel item in result)
                {
                    Console.WriteLine(string.Format("{0},{1},{2},{3}", item.id, item.name, item.sex, item.course));
                }
                Console.WriteLine("全连接");
                result = AllJoin(student, course);
                foreach (ResultModel item in result)
                {
                    Console.WriteLine(string.Format("{0},{1},{2},{3}", item.id, item.name, item.sex, item.course));
                }
                Console.WriteLine("左不包含连接");
                result = LeftOuterJoin(student, course);
                foreach (ResultModel item in result)
                {
                    Console.WriteLine(string.Format("{0},{1},{2},{3}", item.id, item.name, item.sex, item.course));
                }
                Console.WriteLine("右不包含连接");
                result = RightOuterJoin(student, course);
                foreach (ResultModel item in result)
                {
                    Console.WriteLine(string.Format("{0},{1},{2},{3}", item.id, item.name, item.sex, item.course));
                }
                Console.WriteLine("全不包含连接");
                result = AllOuterJoin(student, course);
                foreach (ResultModel item in result)
                {
                    Console.WriteLine(string.Format("{0},{1},{2},{3}", item.id, item.name, item.sex, item.course));
                }
                Console.ReadKey();
            }
    
            public static DataTable GetStudent()
            {
                DataTable student = new DataTable();
                student.Columns.Add("studentId");
                student.Columns.Add("name");
                student.Columns.Add("sex");
                student.Rows.Add(new object[] { "1", "小明", "" });
                student.Rows.Add(new object[] { "2", "小黄", "" });
                student.Rows.Add(new object[] { "3", "小红", "" });
                student.Rows.Add(new object[] { "4", "小杨", "" });
                return student;
            }
    
            public static DataTable GetCourse()
            {
                DataTable course = new DataTable();
                course.Columns.Add("studentId");
                course.Columns.Add("courseName");
                course.Rows.Add(new object[] { "1", "数学" });
                course.Rows.Add(new object[] { "1", "英语" });
                course.Rows.Add(new object[] { "1", "语文" });
                course.Rows.Add(new object[] { "2", "数学" });
                course.Rows.Add(new object[] { "2", "英语" });
                course.Rows.Add(new object[] { "2", "语文" });
                course.Rows.Add(new object[] { "3", "数学" });
                course.Rows.Add(new object[] { "3", "英语" });
                course.Rows.Add(new object[] { "3", "语文" });
                course.Rows.Add(new object[] { "5", "数学" });
                course.Rows.Add(new object[] { "5", "英语" });
                course.Rows.Add(new object[] { "5", "语文" });
                return course;
            }
    
            /// <summary>
            /// 内连接
            /// </summary>
            /// <param name="student"></param>
            /// <param name="course"></param>
            /// <returns></returns>
            public static IEnumerable<ResultModel> InnerJoin(DataTable student, DataTable course)
            {
                //Lambda表达式
                var result = from s in student.Select()
                             join c in course.Select() on s["studentId"].ToString() equals c["studentId"].ToString()
                             select new ResultModel
                             {
                                 id = s["studentId"].ToString(),
                                 name = s["name"].ToString(),
                                 sex = s["sex"].ToString(),
                                 course = c["courseName"].ToString()
                             };
                //查询表达式语法
                result = student.Select()
                    .Join(course.Select(), s => s["studentId"].ToString(), c => c["studentId"].ToString(),
                    (s, c) => new ResultModel
                    {
                        id = s["studentId"].ToString(),
                        name = s["name"].ToString(),
                        sex = s["sex"].ToString(),
                        course = c["courseName"].ToString()
    
                    });
                return result;
            }
    
            /// <summary>
            /// 左连接(左外连接) linq中只有左连接,右连接只要把数据集合顺序倒转就行了
            /// </summary>
            /// <param name="student"></param>
            /// <param name="course"></param>
            /// <returns></returns>
            public static IEnumerable<ResultModel> LeftJoin(DataTable student, DataTable course)
            {
                //Lambda表达式
                var result = from s in student.Select()
                             join c in course.Select() on s["studentId"].ToString() equals c["studentId"].ToString() into temple
                             from t in temple.DefaultIfEmpty()
                             select new ResultModel
                             {
                                 id = s["studentId"].ToString(),
                                 name = s["name"].ToString(),
                                 sex = s["sex"].ToString(),
                                 course = t==null?"Null":t["courseName"].ToString()
                             };
                //查询表达式语法
                result = student.Select().GroupJoin(course.Select(), s => s["studentId"].ToString(), c => c["studentId"].ToString(),
                    (s, c) => new { s, c }).SelectMany(g => g.c.DefaultIfEmpty(), (item, c) => new ResultModel
                    {
                        id = item.s["studentId"].ToString(),
                        name = item.s["name"].ToString(),
                        sex = item.s["sex"].ToString(),
                        course = c == null ? "Null" : c["courseName"].ToString()
    
                    });
                return result;
            }
    
            /// <summary>
            /// 右连接(右外连接)
            /// </summary>
            /// <param name="student"></param>
            /// <param name="course"></param>
            /// <returns></returns>
            public static IEnumerable<ResultModel> RightJoin(DataTable student, DataTable course)
            {
                //Lambda表达式
                var result = from c in course.Select()
                             join s in student.Select() on c["studentId"].ToString() equals s["studentId"].ToString() into temple
                             from t in temple.DefaultIfEmpty()
                             select new ResultModel
                             {
                                 id = t == null ? "Null" : t["studentId"].ToString(),
                                 name = t == null ? "Null" : t["name"].ToString(),
                                 sex = t == null ? "Null" : t["sex"].ToString(),
                                 course = c["courseName"].ToString()
                             };
                //查询表达式语法
                result = course.Select().GroupJoin(student.Select(), s => s["studentId"].ToString(), c => c["studentId"].ToString(),
                    (s, c) => new { s, c }).SelectMany(g => g.c.DefaultIfEmpty(), (item, c) => new ResultModel
                    {
                        id = c == null ? "Null" : c["studentId"].ToString(),
                        name = c == null ? "Null" : c["name"].ToString(),
                        sex = c == null ? "Null" : c["sex"].ToString(),
                        course =item.s["courseName"].ToString()
    
                    });
                return result;
            }
    
            /// <summary>
            /// 全连接(全外连接)
            /// </summary>
            /// <param name="student"></param>
            /// <param name="course"></param>
            /// <returns></returns>
            public static IEnumerable<ResultModel> AllJoin(DataTable student, DataTable course)
            {
                IEnumerable<ResultModel> left = LeftJoin(student, course);
                IEnumerable<ResultModel> right = RightJoin(student, course);
    
                //比较器
                IEqualityComparer<ResultModel> ec = new EntityComparer();
                return left.Union(right, ec);
            } 
    
            /// <summary>
            /// 左不包含连接
            /// </summary>
            /// <param name="student"></param>
            /// <param name="course"></param>
            /// <returns></returns>
            public static IEnumerable<ResultModel> LeftOuterJoin(DataTable student, DataTable course)
            {
                //Lambda表达式
                var result = from s in student.Select()
                             join c in course.Select() on s["studentId"].ToString() equals c["studentId"].ToString() into temple
                             from t in temple.DefaultIfEmpty()
                             where t==null
                             select new ResultModel
                             {
                                 id = s["studentId"].ToString(),
                                 name = s["name"].ToString(),
                                 sex = s["sex"].ToString(),
                                 course ="Null"
                             };
                //查询表达式语法
                result = student.Select().GroupJoin(course.Select(), s => s["studentId"].ToString(), c => c["studentId"].ToString(),
                    (s, c) => new { s, c })
                    .SelectMany(g => g.c.DefaultIfEmpty(), (item, c) => new { item,c}).Where(item => item.c== null)
                    .Select(item=>new ResultModel
                    {
                        id = item.item.s["studentId"].ToString(),
                        name = item.item.s["name"].ToString(),
                        sex = item.item.s["sex"].ToString(),
                        course ="Null"
                    });
                return result;
            }
    
            /// <summary>
            /// 右不包含连接
            /// </summary>
            /// <param name="student"></param>
            /// <param name="course"></param>
            /// <returns></returns>
            public static IEnumerable<ResultModel> RightOuterJoin(DataTable student, DataTable course)
            {
                //Lambda表达式
                var result = from c in course.Select()
                             join s in student.Select() on c["studentId"].ToString() equals s["studentId"].ToString() into temple
                             from t in temple.DefaultIfEmpty()
                             where t==null
                             select new ResultModel
                             {
                                 id = "Null",
                                 name = "Null",
                                 sex = "Null",
                                 course = c["courseName"].ToString()
                             };
                //查询表达式语法
                result = course.Select().GroupJoin(student.Select(), s => s["studentId"].ToString(), c => c["studentId"].ToString(),
                    (s, c) => new { s, c }).SelectMany(g => g.c.DefaultIfEmpty(), (item, c) => new { item, c }).Where(item=>item.c==null)
                    .Select(item => new ResultModel
                    {
                        id ="Null",
                        name ="Null",
                        sex = "Null" ,
                        course = item.item.s["courseName"].ToString()
    
                    });
                return result;
            }
    
            /// <summary>
            /// 全不包含连接
            /// </summary>
            /// <param name="student"></param>
            /// <param name="course"></param>
            /// <returns></returns>
            public static IEnumerable<ResultModel> AllOuterJoin(DataTable student, DataTable course)
            {
                IEnumerable<ResultModel> left = LeftOuterJoin(student, course);
                IEnumerable<ResultModel> right = RightOuterJoin(student, course);
    
                return left.Union(right);
            }
    
            /// <summary>
            /// 交叉连接(笛卡尔积)
            /// </summary>
            /// <param name="student"></param>
            /// <param name="course"></param>
            /// <returns></returns>
            public static IEnumerable<ResultModel> CrossJoin(DataTable student, DataTable course)
            {
                //Lambda表达式
                var result = from s in student.Select()
                             from c in course.Select() 
                             select new ResultModel
                             {
                                 id = s["studentId"].ToString(),
                                 name = s["name"].ToString(),
                                 sex = s["sex"].ToString(),
                                 course = c["courseName"].ToString()
                             };
                //查询表达式语法
                result = student.Select()
                    .SelectMany(c=>course.Select(),
                    (s, c) => new ResultModel
                    {
                        id = s["studentId"].ToString(),
                        name = s["name"].ToString(),
                        sex = s["sex"].ToString(),
                        course = c["courseName"].ToString()
    
                    });
                return result;
            }
    
        }
    
        public class ResultModel
        {
            public string id { get; set; }
            public string name { get; set; }
            public string sex { get; set; }
            public string course { get; set; }
        }
    
        public class EntityComparer : IEqualityComparer<ResultModel>
        {
            public bool Equals(ResultModel a, ResultModel b)
            {
                if (Object.ReferenceEquals(a, b)) return true;
                if (Object.ReferenceEquals(a, null) || Object.ReferenceEquals(b, null))
                    return false;
                return a.id == b.id && a.name == b.name && a.sex == b.sex&&a.course==b.course;
            }
    
            public int GetHashCode(ResultModel a)
            {
                if (Object.ReferenceEquals(a, null)) return 0;
                int hashId = a.id == null ? 0 : a.id.GetHashCode();
                int hashName = a.name == null ? 0 : a.id.GetHashCode();
                int hashSex = a.sex == null ? 0 : a.sex.GetHashCode();
                int hashCourse = a.course == null ? 0 : a.course.GetHashCode();
                return hashId ^ hashName ^ hashSex ^ hashCourse;
            }
        }  
    
    }
    View Code

     

      

      

      

     

  • 相关阅读:
    代码生成器
    怎样成为优秀的软件模型设计者[转]
    2010年部分节假日安排的通知
    Web开发工具整理
    JS模版
    Timer_MinBytesPerSecond,Timer_ConnectionIdle解决办法
    [原]Asp.Net提交后,刷新时事件触发问题解决
    [转]JS日期选择控件
    知道了sa密码,控制服务器
    调试
  • 原文地址:https://www.cnblogs.com/fuhai/p/5629355.html
Copyright © 2020-2023  润新知