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 ...
随机推荐
- 解决前端开发sublime text 3编辑器无法安装插件的问题
今天在笔记本电脑上安装了个sublime,但是却出现无法装插件的问题.于是稍微在网上查了些资料,并试验了一番,写了如下文章. 安装插件的步骤: 弹出 选中install package 如果出现如下问 ...
- StackExchange.Redis学习笔记(五) 发布和订阅
Redis命令中的Pub/Sub Redis在 2.0之后的版本中 实现了 事件推送的 发布订阅命令 以下是Redis关于发布和订阅提供的相关命令 SUBSCRIBE channel [channe ...
- git向码云上传代码总结
1.下载git windows下载地址:https://git-for-windows.github.io/ 2.安装git 一路确定 3.配置git 如果你要使用ssh上传代码,你需要本地生成ssh ...
- 使用python写一个简单的C段扫
纠结C段查询N久..刚刚拿骚棒FD去抓御剑的包,发现emmm...申请了必应的Key 然后去拿必应API查.这里疼[心]原本也想去弄的.但是人懒. 然后就没有然后了. 代码: 生成IP段的脚本图1 # ...
- 在虚拟机中安装metasploit官方攻防模拟器
首先我们要在windwos下载安装perl环境.下载地址: http://pan.baidu.com/s/1i3GLKAp 然后我们安装 点击next 我同意,next next next,然后他会安 ...
- lodash源码分析之缓存方式的选择
每个人心里都有一团火,路过的人只看到烟. --<至爱梵高·星空之谜> 本文为读 lodash 源码的第八篇,后续文章会更新到这个仓库中,欢迎 star:pocket-lodash gitb ...
- Codeforces 791B Bear and Friendship Condition(DFS,有向图)
B. Bear and Friendship Condition time limit per test:1 second memory limit per test:256 megabytes in ...
- bzoj:3392: [Usaco2005 Feb]Part Acquisition 交易
Description 奶牛们接到了寻找一种新型挤奶机的任务,为此它们准备依次经过N(1≤N≤50000)颗行星,在行星上进行交易.为了方便,奶牛们已经给可能出现的K(1≤K≤1000)种货物 ...
- LightOJ1012-Guilty Prince-DFS
Guilty Prince Time Limit: 2 second(s) Memory Limit: 32 MB Once there was a king named Akbar. He had ...
- nodeJs文件系统(fs)与流(stream)
一.简介 本文将介绍node.js文件系统(fs)和流(stream)的一些API已经参数使用情况. 二.目录 文件系统将介绍以下方法: 1.fs.readFile 2.fs.writeFile 3. ...