數據庫和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

 

 

  

  

  

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章