Sql Server的艺术(四) SQL多表查询
表的基本连接
SQL的一个重要特性就是能通过JOIN关键词,从多个交叉表中查询、分析数据。
连接表的目的
在关系数据库中,数据表设计的一个重要原则就是要避免冗余性。
- 减少了冗余信息,节省了数据库存储空间。
- 简化了数据修改、维护操作。
学习本节需要的数据表:
CREATE TABLE TEACHER
(
ID INT IDENTITY (,) PRIMARY KEY , --主键,自增长
TNO INT NOT NULL, --教工号
TNAME CHAR() NOT NULL, --教师姓名
CNO INT NOT NULL, --课程号
SAL INT, --工资
DNAME CHAR() NOT NULL, --所在系
TSEX CHAR() NOT NULL, --性别
AGE INT NOT NULL --年龄
)
INSERT INTO dbo.TEACHER VALUES( ,'王军',,,'数学','男',)
INSERT INTO dbo.TEACHER VALUES( ,'李彤',,,'生物','女',)
INSERT INTO dbo.TEACHER VALUES( ,'王永军',,,'计算机','女',)
INSERT INTO dbo.TEACHER VALUES( ,'刘晓婧',,,'计算机','女',)
INSERT INTO dbo.TEACHER VALUES( ,'高维',,,'电子工程','男',)
INSERT INTO dbo.TEACHER VALUES( ,'李伟',,,'机械工程','女',)
INSERT INTO dbo.TEACHER VALUES( ,'刘辉',,,'生物','女',)
INSERT INTO dbo.TEACHER VALUES( ,'刘伟',,,'计算机','男',)
INSERT INTO dbo.TEACHER VALUES( ,'刘静',,,'经济管理','男',)
INSERT INTO dbo.TEACHER VALUES( ,'刘奕锴',,,'计算机','女',)
INSERT INTO dbo.TEACHER VALUES( ,'高维',,,'经济管理','男',) CREATE TABLE COURSE
(
ID INT IDENTITY (,) PRIMARY KEY , --主键,自增长
CNO INT NOT NULL, --课程号
CNAME CHAR() NOT NULL, --课程名称
CTIME INT NOT NULL, --学时
SCOUNT INT NOT NULL, --容纳人数
CTEST SMALLDATETIME NOT NULL, --考试时间
)
INSERT INTO dbo.COURSE VALUES( ,'应用数学基础',,,'2006-7-10')
INSERT INTO dbo.COURSE VALUES( ,'生物工程概论',,,'2006-7-8')
INSERT INTO dbo.COURSE VALUES( ,'计算机软件基础',,,'2006-7-8')
INSERT INTO dbo.COURSE VALUES( ,'计算机硬件基础',,,'2006-6-28')
INSERT INTO dbo.COURSE VALUES( ,'模拟电路设计',,,'2006-7-10')
INSERT INTO dbo.COURSE VALUES( ,'机械设计实践',,,'2006-7-14')
INSERT INTO dbo.COURSE VALUES( ,'生物化学',,,'2006-7-2')
INSERT INTO dbo.COURSE VALUES( ,'数据库设计',,,'2006-7-1')
INSERT INTO dbo.COURSE VALUES( ,'设计理论',,,'2006-6-30')
INSERT INTO dbo.COURSE VALUES( ,'计算机入门',,,'2006-6-29')
INSERT INTO dbo.COURSE VALUES( ,'数字电路设计基础',,,'2006-6-20')
CREATE TABLE STUDENT
(
ID INT IDENTITY(,) PRIMARY KEY NOT NULL,
SNO CHAR() NOT NULL, --学号
SNAME CHAR() NOT NULL, --姓名
DNAME CHAR() NOT NULL, --系
SSEX CHAR() NOT NULL, --性别
CNO INT , --课程号
MARK DECIMAL(,), --成绩
TYPE CHAR() --课程类型
)
INSERT INTO dbo.STUDENT VALUES('','刘建国','管理工程','男',,82.5,'必修')
INSERT INTO dbo.STUDENT VALUES('','刘建国','管理工程','男',,,'选修')
INSERT INTO dbo.STUDENT VALUES('','刘建国','管理工程','男',,78.5,'选修')
INSERT INTO dbo.STUDENT VALUES('','李春','环境工程','女',,,'必修')
INSERT INTO dbo.STUDENT VALUES('','李春','环境工程','女',,,'选修')
INSERT INTO dbo.STUDENT VALUES('','王天','生物','男',,48.5,'必修')
INSERT INTO dbo.STUDENT VALUES('','王天','生物','男',,,'选修')
INSERT INTO dbo.STUDENT VALUES('','李华','计算机','女',,,'必修')
INSERT INTO dbo.STUDENT VALUES('','李华','计算机','女',,,'必修')
INSERT INTO dbo.STUDENT VALUES('','李华','计算机','女',,,'必修')
INSERT INTO dbo.STUDENT VALUES('','李华','计算机','女',,,'必修')
INSERT INTO dbo.STUDENT VALUES('','李华','计算机','女',,,'选修')
INSERT INTO dbo.STUDENT VALUES('','孙庆','电子工程','男',,,'必修')
INSERT INTO dbo.STUDENT VALUES('','孙庆','电子工程','男',,,'必修')
INSERT INTO dbo.STUDENT VALUES('','孙庆','电子工程','男',,,'必修')
INSERT INTO dbo.STUDENT VALUES('','孙庆','电子工程','男',,,'必修')
INSERT INTO dbo.STUDENT VALUES('','高伟','机械工程','男',,,'必修')
INSERT INTO dbo.STUDENT VALUES('','高伟','机械工程','男',,88.5,'必修')
INSERT INTO dbo.STUDENT VALUES('','高伟','机械工程','男',,,'选修')
INSERT INTO dbo.STUDENT VALUES('','高伟','机械工程','男',,,'选修')
数据表
1、简单的二表连接
SELECT TNAME,DNAME,CNAME,CTEST FROM dbo.TEACHER,dbo.COURSE WHERE dbo.TEACHER.CNO=dbo.COURSE.CNO --查询老师和系表的数据
根据以上SQL,可知道执行过程:
- 系统首先执行FROM子句,这里FROM子句列出的有两个表TEACHER和COURSE,DBMS将计算这两个表的笛卡儿积,列出这两个表中行的所有可能组合,形成一个中间表。中间表的每条记录包含了两个表中的所有行。
- 而后系统将执行WHERE子句,根据“dbo.TEACHER.CNO=dbo.COURSE.CNO”关系对中间表进行搜索,去除那些不满足该条件的记录。
- 最后系统执行SELECT语句,从执行WHERE子句后得到的中间表的每条记录中,提取TNAME,DNAME,CNAME,CTEST这4个字段的信息作为结果表。
注意:
由于两张表都存在相同的字段CNO,所以在查询的时候要指明来自哪张表,如dbo.TEACHER.CNO、dbo.COURSE.CNO,而其他具有重名的字段,也要进行同样的处理,否则会报错。
问题:
表的连接时一句关系WHERE子句来定义的,实际开发中,也一定更要用到关系连接。如果不指明连接关系呢?
SELECT TNAME,DNAME,CNAME,CTEST FROM dbo.TEACHER,dbo.COURSE
SELECT COUNT(*) AS 总条数 FROM dbo.TEACHER,dbo.COURSE --查询一共有几条数据
2、三表查询(在WHERE子句中进行夺标查询)
SELECT SNAME,dbo.STUDENT.SNAME,CNAME,CTEST,MARK,dbo.TEACHER.TNAME FROM dbo.TEACHER,dbo.COURSE,dbo.STUDENT WHERE dbo.TEACHER.CNO=dbo.COURSE.CNO AND dbo.COURSE.CNO=dbo.STUDENT.CNO 使用别名,S,T,C
SELECT SNAME,S.SNAME,CNAME,CTEST,MARK,TNAME FROM dbo.TEACHER AS T,dbo.COURSE AS C,dbo.STUDENT AS S WHERE T.CNO=C.CNO AND C.CNO=S.CNO
”dbo.TEACHER.CNO=dbo.COURSE.CNO AND dbo.COURSE.CNO=dbo.STUDENT.CNO“,含义为”只有同时存在TEACHER,STUDENT,COURSE“中CNO的信息才会作为结果显示出来。
注意:
由于学生表和老师表都有字段”DNAME“,在SELECT子句中查询DNAME字段时,我们要指定表名,否则系统会报错。
可见,创建表的基本连接,只要遵守下面的基本原则即可:
- FROM子句中应列出所有连接的表的表名。
- WHERE子句应定义连接的关联条件。
- 当列名为多个表共有时,要指明列的所在表,即采用”表名.字段名“的形式。
3、采用JOIN关键字建立连接
SELECT COLUMN
FROM join_table
JOIN_TYPE join_table
ON (join_condition)
说明如下:
- join_table指出参与连接操作的表名。
- JOIN_TYPE为连接类型,可分为四种:自然连接、内连接、外连接和交叉连接。
- 自然连接JOIN_TYPE的形式为NATURAL JOIN
- 内连接JOIN_TYPE的形式为INNER JOIN
- 外连接,又分为左连接,JOIN_TYPE形式为LEFT OUTER JOIN或LEFT JOIN;右连接,JOIN_TYPE的形式为RIGHT OUTER JOIN或RIGHT JOIN;全外连接,JOIN_TYPE的形式为CROSS JOIN;全外连接,JOIN_TYPE的形式为FULL OUTER JOIN或FULL JOIN。
- 交叉连接中JOIN_TYPE的形式为CROSS JOIN。
- ON(join_condition)子句指出连接条件,由被连接表中的列和比较远算符、逻辑运算符等构成。
4、表的连接类型
4.1、自连接
SELECT DISTINCT SNO FROM dbo.STUDENT WHERE MARK< --查询不及格学生学号,重复的去除
SELECT DNAME,MARK,SNAME,CNO FROM dbo.STUDENT WHERE SNO IN('','','') AND MARK < --查询三个学号中不及格学生的信息
4.2、内连接(INNER JOIN)
内连接也称为等同连接,返回的结果集是两个表中所有相匹配的数据,而舍弃不匹配的数据。查询的结果表包含的两源表行,必须满足ON子句中的搜索条件。
使用等于号(=)比较被连接列的列值,在查询结果中列出被连接表中的所有列,包括其中的重复列。图给出了典型的等值内连接示意图。
SELECT s.SNAME,s.DNAME,s.CNO,t.TNAME FROM dbo.STUDENT AS s inner join dbo.TEACHER AS t ON t.CNO = s.CNO --查询两表部分信息
使用不等连接进行查询 后面会讲到各种运算符 先给官方网站地址:http://www.runoob.com/sqlite/sqlite-operators.html
SELECT s.SNAME,s.DNAME,s.CNO,t.TNAME FROM dbo.STUDENT AS s inner join dbo.TEACHER AS t ON s.DNAME<>t.DNAME AND t.CNO = s.CNO
等价于:
SELECT s.SNAME,s.DNAME,s.CNO,t.TNAME FROM dbo.STUDENT AS s,dbo.TEACHER AS t WHERE s.DNAME<>t.DNAME AND t.CNO = s.CNO
DBMS默认多表查询按INNER JOIN来执行,除非指定OUTER JOIN。
注意:
INNER JOIN可以实现夺标查询,但是一次只能连接两张表,要连接多表,必须进行多次连接。
4.2.1、使用INNER JOIN实现多表连接
--三张表进行查询,用两个INNER JOIN
SELECT s.SNAME,s.DNAME,c.CNAME,c.CTEST,s.MARK,t.TNAME FROM dbo.TEACHER AS t INNER JOIN dbo.COURSE AS c ON c.CNO = t.CNO INNER JOIN dbo.STUDENT AS s ON s.CNO = t.CNO
4.3、外连接(OUTER JOIN)
左外连接=内连接+左边表中失配的元组
右外连接=内连接+右边表中失配的元组
全外连接=内连接+左边表中失配的元组+右边表中失配的元组
表达式示意图如:
SELECT s.SNO,s.SNAME,c.CNO,c.CNAME,c.CTEST,s.MARK FROM dbo.STUDENT AS s LEFT OUTER JOIN dbo.COURSE AS c ON c.CNO = s.CNO
在WHERE子句中用”*=“实现左外连接
SELECT s.SNO,s.SNAME,c.CNO,c.CNAME,c.CTEST,s.MARK FROM dbo.STUDENT AS s,dbo.COURSE AS c WHERE c.CNO *= s.CNO
----三种连接方式都一样,只需要改”LEFT OUTER JOIN“为”RIGHT OUTER JOIN“和”FULL OUTER JOIN“,
就不做三个演示了,可以自己对比数据的异同
4.4、交叉连接(CROSS JOIN)
除了在FROM子句中使用逗号间隔连接的表外,SQL还支持另一种被称为交叉连接的操作,它们都返回被连接的两个表所有数据行的笛卡尔积,返回到的数据行数等于第一个表中符合查询条件的数据行数乘以第二个表中符合查询条件的数据行数。惟一的不同在于,交叉连接分开列名时,使用CROSS JOIN关键字而不是逗号。
实际上,下面两个表达式是等价的。
SELECT * FROM table1, table2
SELECT * FROM table1 CROSS JOIN table2
交叉连接示意图:
SELECT s.SNO,s.SNAME,c.CNO,s.CNO,c.CNAME,c.CTEST,s.MARK FROM dbo.STUDENT AS s CROSS JOIN dbo.COURSE AS c WHERE s.CNO=c.CNO AND s.MARK>
注意:
在使用CROSS JOIN关键字交叉连接表时,因为生成的是两个表的笛卡尔积,因而不能使用ON关键字,只能在WHERE子句中定义搜索条件。
事实上,直接使用CROSS JOIN很少得到想要的结果,但是,正如实例所示,作为查询的第一步,DBMS通常在FROM子句中,对连接的表进行CROSS JOIN,然后过滤得到的中间表。
Sql Server的艺术(四) SQL多表查询的更多相关文章
- 数据库SQL Server2012笔记(四)——多表查询、子查询、分页查询、用查询结果创建新表和外连接
1.多表查询 1)笛卡尔集: select * from 表名1,表名2 select * from 表名1.表名2 where 表名1.字段名=表名2.字段名 注: 若有两张表有同 ...
- SQL Server进阶(三)单表查询
示例数据库 点我下载 一条完整的sql语句 select top | distinct 字段, 表达式, 函数, ... from 表表达式 where 筛选条件 group by 分组条件 havi ...
- SQL server分页的四种方法
SQL server分页的四种方法 1.三重循环: 2.利用max(主键); 3.利用row_number关键字: 4.offset/fetch next关键字 方法一:三重循环思路 先取前20页, ...
- 从0开始搭建SQL Server AlwaysOn 第四篇(配置异地机房节点)
从0开始搭建SQL Server AlwaysOn 第四篇(配置异地机房节点) 第一篇http://www.cnblogs.com/lyhabc/p/4678330.html第二篇http://www ...
- SQL Server 2008 R2中,变表的右键弹出菜单中的“选择前1000行”为“选择所有行”
原文:SQL Server 2008 R2中,变表的右键弹出菜单中的"选择前1000行"为"选择所有行" 从SQL Server 2008开始,微软为了提高查询 ...
- 何查询SQL Server数据库没有主键的表并增加主键
SQL Server数据库中,如果一个表没有主键,我们该如何查询呢?本文我们主要就介绍了如何查询数据库中没有主键的表名并为其增加主键的方法,希望能够对您有所帮助. 该功能的实现代码如下: declar ...
- SQL server学习(四)T-SQL编程之事务、索引和视图
今天来分享下T-SQL高级编程中的事务.索引.视图,可以和之前的SQL server系列文章结合起来. 一.事务 事务(TRANSACTION)是作为单个逻辑工作单元执行的一系列操作,这些操作作为一个 ...
- SQL SERVER 判断是否存在数据库、表、列、视图
SQL SERVER 判断是否存在数据库.表.列.视图 --1. 判断数据库是否存在 IF EXISTS (SELECT * FROM SYS.DATABASES WHERE NAME = '数据库名 ...
- SQL SERVER学习笔记:临时表与表变量
本文主要摘自徐海蔚的<Microsoft SQL SERVER企业级平台管理实践> 表变量可以作为存储过程的返回参数,而临时表不行.(存疑?表值参数只在SQL SERVER2008才开始支 ...
- .net(C#数据库访问) Mysql,Sql server,Sqlite,Access四种数据库的连接方式
便签记录Mysql,Sql server,Sqlite,Access四种数据库的简单连接方式 //using MySql.Data.MySqlClient; #region 执行简单SQL语句,使用M ...
随机推荐
- Java中组合 设计技巧 实例
关于组合 和 集成 先放两篇文章:这两篇文章写的太好了. http://blog.csdn.net/u013905744/article/details/51752044 Java的组合(持有对 ...
- 初学HTML5,你要懂得哪些?
很多人问过我这个问题,想要做HTML5页面你要懂得哪些知识?而问这个问题的人基本上都是刚听说过或刚接触HTML5,处在迷茫的阶段,他们往往会被一些网上炫酷页面所吸引,然后自己也想学习HTML5,能通过 ...
- 用户空间网络提升 NFV 的性能
本文是一篇翻译,翻译自https://software.intel.com/en-us/blogs/2015/06/12/user-space-networking-fuels-nfv-perform ...
- 浅析ASCII、Unicode和UTF-8三种常见字符编码
什么是字符编码? 计算机只能处理数字,如果要处理文本,就必须先把文本转换为数字才能处理.最早的计算机在设计时采用8个比特(bit)作为一个字节(byte),所以,一个字节能表示的最大的整数就是255( ...
- BZOJ3109: [cqoi2013]新数独
题目:http://www.lydsy.com/JudgeOnline/problem.php?id=3109 搜索一遍.读入注意一下.. #include<cstring> #inclu ...
- android文件管理器源码、斗鱼直播源码、企业级erp源码等
Android精选源码 文件清理管理器 自定义水平带数字的进度条以及自定义圆形带数字的进度条 利用sectionedRecyclerViewAdapter实现分组列表的recyclerView源码 流 ...
- Winform & Devexpress Chart使用入门
一.Chart(Winform) 使用图表控件(chart)首先要理解图表区域(ChartArea).XY轴(AxisX.AxisY).数据点(Series).标题(Title).图例(Legend) ...
- tomcat服务器一闪而过解决方法
JDK没有配置,下载JDK安装到电脑上,然后在电脑->属性->高级系统设置->环境变量,将JDK中bin文件的目录E:\Program Files (x86)\Java\jre7\b ...
- 用php怎样将图片gif转化为jpg
<?php $input= "link2.gif"; $output='test.jpg' ; $image=imagecreatefromgif($input); imag ...
- OpenCV鼠标滑轮事件
鼠标的滑轮事件实现图像的缩放很方便,具体在回调函数中如下写: 其中scale可以在外部定义为全局变量,通过响应CV_EVENT_MOUSEWHEEL滑轮事件获取Scale的具体值. 获取Scale值需 ...