我对多表关联的总结://以下若有理解错误请指出,谢谢!
内连接
INNER JOIN:只显示多表之间与关联条件相匹配的列.
外连接:
LEFT JOIN :以左表为基础,显示左表中的所有列,不管是否与关联条件相匹配,而右表中的数据只显示与关联条件相匹配的列,不匹配的列以NULL字符填充.
RIGHT JOIN:以右表为基础,显示右表中的所有列,不管是否与关联条件相匹配,而左表中的数据只显示与关联条件相匹配的列,不匹配的列以NULL字符填充.
FULL JOIN :显示多个表中的所有的列,不匹配关联条件的列以NULL字符填充.
下面是我写的关于sql 多表关联的sql语句,大家可以在SQL SERVER中操作下试下,是否与上面的对于sql关联的总结相同,查询结果我就不结了,大家试下就知道了!
create database mydb;
use mydb;
create table customers
(
cust_id int not null identity(1,1) primary key,
cust_name varchar(100) not null,
cust_tel varchar(50) not null,
cust_address varchar(100) not null
)
create table books
(
isbn int not null identity(700001,1),
book_name varchar(100) not null,
price money not null
)
create table orders
(
order_id int not null identity(1001,1),
isbn int not null,
cust_id int not null,
order_date datetime not null
)
insert into customers(cust_name,cust_tel,cust_address) values('书店a','0553-2451466','江苏省');
insert into customers(cust_name,cust_tel,cust_address) values('书店b','0553-2215266','江苏省');
insert into customers(cust_name,cust_tel,cust_address) values('书店c','0553-8754466','江苏省');
insert into customers(cust_name,cust_tel,cust_address) values('书店d','0553-4563466','江苏省');
insert into customers(cust_name,cust_tel,cust_address) values('书店e','0553-2145212','江苏省');
insert into books(book_name,price) values('php',78);
insert into books(book_name,price) values('java',72);
insert into books(book_name,price) values('c++',72);
insert into books(book_name,price) values('C语言',56);
insert into books(book_name,price) values('sql',53);
insert into books(book_name,price) values('asp.net',69);
insert into books(book_name,price) values('asp',43);
insert into orders(isbn,cust_id,order_date) values(700001,1,getdate());
insert into orders(isbn,cust_id,order_date) values(700002,1,getdate());
insert into orders(isbn,cust_id,order_date) values(700003,2,getdate());
insert into orders(isbn,cust_id,order_date) values(700001,1,getdate());
insert into orders(isbn,cust_id,order_date) values(700003,1,getdate());
insert into orders(isbn,cust_id,order_date) values(700006,1,getdate());
insert into orders(isbn,cust_id,order_date) values(700001,2,getdate());
insert into orders(isbn,cust_id,order_date) values(700001,2,getdate());
insert into orders(isbn,cust_id,order_date) values(700002,2,getdate());
insert into orders(isbn,cust_id,order_date) values(700003,1,getdate());
insert into orders(isbn,cust_id,order_date) values(700003,9,getdate());--我下面是故意的,让大家看到效果
insert into orders(isbn,cust_id,order_date) values(7000025,9,getdate());
select a.order_id,a.isbn,b.book_name,b.price,c.cust_name,c.cust_tel,c.cust_address,a.order_date
from orders as a inner join books as b
on
a.isbn=b.isbn inner join customers as c
on
a.cust_id=c.cust_id;
select a.order_id,a.isbn,b.book_name,b.price,c.cust_name,c.cust_tel,c.cust_address,a.order_date
from orders as a left join books as b
on
a.isbn=b.isbn left join customers as c
on
a.cust_id=c.cust_id;
select a.order_id,a.isbn,b.book_name,b.price,c.cust_name,c.cust_tel,c.cust_address,a.order_date
from orders as a right join books as b
on
a.isbn=b.isbn right join customers as c
on
a.cust_id=c.cust_id;
左表右表指哪些表?
select * from
table_1 as a left join table_2 as c
on
a.id=b.id
leftjoin table_3 as c
on
b.isbn=c.isbn
疑问中............
第一种认为:
认为最左边的表左表 table_1
右表就是除了左表的其它表,而不是最右边的表
所以这里的左表是 table_1,那右表是table_2,table_3
第二种认为:
table_1 是table_2的左表,table_2是table_3的左表
CSDN SQL专区提问,竟请您的加盟:http://community.csdn.net/Expert/topic/5696/5696608.xml?temp=.4501764
还请牛人指点!
最终答案:
table_1 左连接 table_2 以table_1为基础进行连接运算,得到新表即临时表(#table)。
#table 左连接 table_3 以table# 为基础进行连接运算,得到最终结果。
与我的总结一致!
以下是来自网上的关于关联说的比较好的文章(易懂)
来自:http://www.cnblogs.com/temptation/archive/2006/05/23/407328.aspx
表A记录如下:
aID aNum
1 a20050111
2 a20050112
3 a20050113
4 a20050114
5 a20050115
表B记录如下:
bID bName
1 2006032401
2 2006032402
3 2006032403
4 2006032404
8 2006032408
实验如下:
1. left join
sql语句如下:
SELECT * FROM A
LEFT JOIN B
ON A.aID = B.bID
结果如下:
aID aNum bID bName
1 a20050111 1 2006032401
2 a20050112 2 2006032402
3 a20050113 3 2006032403
4 a20050114 4 2006032404
5 a20050115 NULL NULL
(所影响的行数为 5 行)
结果说明:
left join是以A表的记录为基础的,A可以看成左表,B可以看成右表,left join是以左表为准的.
换句话说,左表(A)的记录将会全部表示出来,而右表(B)只会显示符合搜索条件的记录(例子中为: A.aID = B.bID).
B表记录不足的地方均为NULL.
2. right join
sql语句如下:
SELECT * FROM A
RIGHT JOIN B
ON A.aID = B.bID
结果如下:
aID aNum bID bName
1 a20050111 1 2006032401
2 a20050112 2 2006032402
3 a20050113 3 2006032403
4 a20050114 4 2006032404
NULL NULL 8 2006032408
(所影响的行数为 5 行)
结果说明:
仔细观察一下,就会发现,和left join的结果刚好相反,这次是以右表(B)为基础的,A表不足的地方用NULL填充.
3.inner join
sql语句如下:
SELECT * FROM A
INNERJOIN B
ON A.aID = B.bID
结果如下:
aID aNum bID bName
1 a20050111 1 2006032401
2 a20050112 2 2006032402
3 a20050113 3 2006032403
4 a20050114 4 2006032404
结果说明:
很明显,这里只显示出了 A.aID = B.bID的记录.这说明inner join并不以谁为基础,它只显示符合条件的记录.
-----------------[以下为网上的一点资料]------------------
LEFT JOIN操作用于在任何的 FROM 子句中,组合来源表的记录。使用 LEFT JOIN 运算来创建一个左边外部联接。左边外部联接将包含了从第一个(左边)开始的两个表中的全部记录,即使在第二个(右边)表中并没有相符值的记录。
语法:
FROM table1 LEFT JOIN table2 ON table1.field1 compopr table2.field2
说明:
① table1, table2参数用于指定要将记录组合的表的名称。
② field1, field2参数指定被联接的字段的名称。且这些字段必须有相同的数据类型及包含相同类型的数据,但它们不需要有相同的名称。
③ compopr参数指定关系比较运算符:"=", "<", ">", "<=", ">=" 或 "<>"。
④ 如果在INNER JOIN操作中要联接包含Memo 数据类型或 OLE Object 数据类型数据的字段,将会发生错误。
9.2.5 采用JOIN关键字建立连接
前面介绍的表的连接,是通过FROM子句列出要连接的表、WHERE子句列出连接条件来实现的。也可以在FROM子句中,通过连接关键字实现表的连接,这样有助于将连接操作与WHERE的搜索条件区分开来。语法如下。
SELECT column说明如下。
join_table指出参与连接操作的表名。
JOIN_TYPE为连接类型,可分为4种:自然连接、内连接、外连接和交叉连接。其中:
自然连接JOIN_TYPE的形式为NATURAL JOIN;
内连接JOIN_TYPE的形式为INNER JOIN;
外连接,又分为左外连接,JOIN_TYPE的形式为LEFT OUTER JOIN或LEFT JOIN;右外连接,JOIN_TYPE的形式为RIGHT OUTER JOIN或RIGHT JOIN;全外连接,JOIN_ TYPE的形式为FULL OUTER JOIN或FULL JOIN;
交叉连接中JOIN_TYPE的形式为CROSS JOIN。
ON (join_condition) 子句指出连接条件,由被连接表中的列和比较运算符、逻辑运算符等构成。
在下节将详细介绍各种连接类型。
9.3 表的连接类型
9.3.1 自连接
自连接是指表与其自身进行连接,这就需要用到前面介绍的表别名。下面通过一个具体实例来讲解自连接的应用。
实例5 自连接的使用方法
查询成绩中存在不及格课程的学生的姓名、所在系、所有的课程及成绩信息。如果采用前面介绍的SELECT语句查询方法,该实例的实现要分为两步。
1.查询存在不及格课程的学生的学号
之所以查询学号,是因为学号是学生的惟一标识信息。代码:
SELECT DISTINCT SNO运行结果如图9.5所示。
图9.5 不及格课程学生的学号
注意 因为可能有的学生的不及格课程多于1门,因此在SELECT子句中使用了DISTINCT关键词,去除重复的学号。
2.根据学号查询相关信息
根据查询的学号结果,查询这些学号的学生的姓名、所在系、所有所修课程及成绩信息。代码:
SELECT SNAME, DNAME, CNO, MARK运行结果如图9.6所示。
图9.6 根据学号查询的相关信息
而如果采用表的自连接,只要通过一步查询就可以实现该实例。代码:
SELECT DISTINCT S1.SNAME, S1.DNAME, S1.CNO, S1.MARK运行结果如图9.7所示。
代码中,FROM子句中的两个表实际上都是表STUDENT。为了独立地使用它们,采用上节介绍的表别名方法,分别为其取别名S1和S2。这样就可以在WHERE子句中,使用S2设定分数查询条件,而在SELECT子句中,使用S1查询满足条件的结果。
需要说明一点,SELECT子句同样要有关键字DISTINCT,如果没有使用DISTINCT关键字,如下面的代码:
图9.7 采用表的自连接执行的查询结果
SELECT S1.SNAME, S1.DNAME, S1.CNO, S1.MARK运行结果如图9.8所示。
图9.8 采用表的自连接但没有去除重复记录的查询结果
可以发现,结果表中出现了重复的记录。下面分析一下代码的执行过程,从中就不难发现重复记录产生的原因。
系统首先执行FROM子句,将STUDENT表S1与它自身S2的笛卡尔积,作为中间表。实际上,该中间表的每一条记录包含两部分信息,一部分是 S1的记录,一部分是S2的记录。而后执行WHERE子句,在中间表中,搜索S2中成绩低于60分的学生的记录,同时要求记录中S1与S2是同一个学生的记录即学号相同。最后执行SELECT语句,从中间表获取S1中相应的信息作为结果表。
当执行WHERE子句,从中间表中逐条搜索S2中成绩低于60分的学生的记录时,由于孙庆有两门课程不及格,所以对于每门不及格的记录都满足搜索条件,因此导致了从S1得到的信息中出现了重复记录。
简单来说,中间表是没有重复记录的,但是S1部分字段是有重复的,而结果集提取的只是S1部分的字段,因此就有可能有重复记录。
注意 一般情况下,自连接也可以使用子查询的方式实现,关于子查询在第10章会详细介绍。
9.3.2 自然连接(NATURAL JOIN)
自然连接(NATURAL JOIN)是一种特殊的等价连接,它将表中具有相同名称的列自动进行记录匹配。自然连接不必指定任何同等连接条件。图9.9给出了典型的自然连接示意图。
图9.9 自然连接
自然连接自动判断相同名称的列,而后形成匹配。缺点是,虽然可以指定查询结果包括哪些列,但不能人为地指定哪些列被匹配。另外,自然连接的一个特点是连接后的结果表中匹配的列只有一个,如图9.9所示,在自然连接后的表中,只有一列C。
实例6 使用NATURAL JOIN进行查询
从STUDENT表和TEACHER表中查询学生姓名、所在系、所修的本系教师开设的课程的课程号以及开课教师姓名。这时候就可以采用NATURAL JOIN对两个表进行自然连接。实例代码:
SELECT SNAME, DNAME, CNO, TNAME当DBMS执行查询时,将把来自STUDENT表的行与来自TEACHER表中的行通过CNO和DNAME列进行匹配连接。即只有两个表中的CNO 和DNAME列的值都相等的行,才连接起来,作为结果表中的行,而CNO和DNAME列在结果表中只出现一次,因此在查询时就不需指明 TEACHER.DNAME或是STUDENT.DNAME。
注意 有些DBMS产品,如SQL Server,不支持NATURAL JOIN连接符,因此这里无法给出该实例代码的运行结果。
事实上,使用NATURAL JOIN运算符进行自然连接,与检查两个源表中同名列值相等的WHERE子句是等价的。因此,上例的实现也可表示如下。
SELECT SNAME, S.DNAME, S.CNO, TNAME运行结果如图9.10所示:
图9.10 另一种自然连接的查询结果
与自然连接不同,采用这种方式进行表的连接,虽然两表的CNO和DNAME列相等,但它们在结果表中出现了两次,因此在SELECT语句中,如果要查询这两个字段,必须指明是哪个表的字段。
事实上,使用基于WHERE子句的等值连接要比使用NATURAL JOIN运算符进行自然连接要灵活得多。正如前面介绍的,使用NATURAL JOIN运算符自动判断出具有相同名称的列,而后形成匹配,不能人为地指定哪些列被匹配。当自然连接STUDENT表和TEACHER表时,CNO和 DNAME列同时被匹配,而不能只匹配一列。而使用WHERE子句则可以实现任意列的匹配。
实例7 使用WHERE子句进行等值连接查询
从STUDENT表和TEACHER表中查询学生姓名、所在系、所修的所有课程的课程号以及开课教师姓名。这时,STUDENT表和TEACHER表只需将CNO字段匹配即可。实例代码:
SELECT SNAME, S.DNAME, S.CNO, TNAME运行结果如图9.11所示。
图9.11 STUDENT表和TEACHER表匹配CNO字段的查询结果
在这种情况下,就不可能使用NATURAL JOIN运算符实现。
9.3.3 内连接(INNER JOIN)
内连接也称为等同连接,返回的结果集是两个表中所有相匹配的数据,而舍弃不匹配的数据。也就是说,在这种查询中,DBMS只返回来自源表中的相关的行,即查询的结果表包含的两源表行,必须满足ON子句中的搜索条件。作为对照,如果在源表中的行在另一表中没有对应(相关)的行,则该行就被过滤掉,不会包括在结果表中。内连接使用比较运算符来完成。内连接可分为两种。
1.等值连接
使用等于号(=)比较被连接列的列值,在查询结果中列出被连接表中的所有列,包括其中的重复列。图9.12给出了典型的等值内连接示意图。
图9.12 等值内连接
实例8 使用INNER JOIN内连接查询
从STUDENT表和TEACHER表中查询学生姓名、所在系、所修的所有课程的课程号以及开课教师姓名。在9.3.2节已经通过WHERE子句实现了该实例,这里通过INNER JOIN内连接两表来实现。实例代码:
SELECT SNAME, S.DNAME, S.CNO, TNAME运行结果如图9.13所示。
图9.13 使用INNER JOIN实现的查询结果
可以看到,通过INNER JOIN内连接两表也得到了同样的结果。
2.不等连接
在连接条件中,可以使用其他比较运算符,比较被连接的列的列值。这些运算符包括>、>=、<=、<、!>、!<和<>。
实例9 使用不等连接进行查询
查询学生修的非本系教师开设的课程信息,包括学生学号、姓名、所在系、课程号、成绩、以及开课教师的姓名信息。实例代码:
SELECT S.SNO, SNAME, S. DNAME, S.CNO, MARK, TNAME运行结果如图9.14所示。
图9.14 不等连接的查询结果
说明 在默认情况下,DBMS将多表查询按INNER JOIN来执行,除非指定OUTER JOIN。即,如果将上例中的INNER JOIN关键字替换为JOIN也会得到同样的结果。
当然也可以使用WHERE子句实现上例。代码如下。
SELECT S.SNO, SNAME, S. DNAME, S.CNO, MARK, TNAME运行结果如图9.15所示。
当然,使用INNER JOIN也可以实现多表的内连接,但是INNER JOIN一次只能连接两个表,要连接多表,必须进行多次连接。
图9.15 使用WHERE子句实现的不等连接
实例10 使用INNER JOIN实现多表的内连接
根据TEACHER表、COURSE表和STUDENT表,查询所有学生的姓名、所在系、所修课程、考试时间、课程成绩及授课教师姓名。该列与 9.2.3节的实例完全相同,只是在9.2.3节采用WHERE子句的方式实现,这里采用INNER JOIN内连接的方式实现,代码如下。
SELECT SNAME, STUDENT.DNAME, CNAME, CTEST, MARK, TNAME运行结果如图9.16所示。
图9.16 使用INNER JOIN实现内连接查询结果
9.3.4 外连接(OUTER JOIN)
不管是内连接还是带WHERE子句的多表查询,都组合自多个表,并生成结果表。换句话说,如果任何一个源表中的行在另一个源表中没有匹配,DBMS将不把该行放在最后的结果表中。
而外连接告诉ODBC生成的结果表,不仅包含符合连接条件的行,而且还包括左表(左外连接时)、右表(右外连接时)或两个边接表(全外连接)中的所有数据行。
SQL的外连接共有3种类型:左外连接,关键字为LEFT OUTER JOIN、右外连接,关键字为RIGHT OUTER JOIN和全外连接,关键字为FULL OUTER JOIN。外连接的用法和内连接一样,只是将INNER JOIN关键字替换为相应的外连接关键字即可。
说明 使用外连接时,关键字OUTER是可选的,如可用LEFT JOIN替代LEFT OUTER JOIN。
下面分别介绍一下这几种外连接方式。
1.左外连接
左外连接,LEFT OUTER JOIN,告诉DBMS生成的结果表中,除了包括匹配行外,还包括JOIN关键字(FROM子句中)左边表的不匹配行。左外连接实际上可以表示为:
左外连接 = 内连接 + 左边表中失配的元组
其中,缺少的右边表中的属性值用NULL表示。图9.17给出了典型的左外连接示意图。
图9.17 左外连接
实例11 左连接STUDENT表和COURSE表
左连接STUDENT表和COURSE表,查询所有同学的学号、姓名、课程代码、课程名称、考试时间和成绩信息。实例代码:
SELECT S.SNO, SNAME, S.CNO, CNAME, CTEST, MARK运行结果如图9.18所示。
可见,最终得到的结果表中,除了包括两个表匹配的行(3~20行),还包括了左边表STUDENT中的不匹配行(1、2行),缺少的右边表,即COURSE表中的属性值用NULL表示。
技巧 在SQL Server中,可以在WHERE子句中使用“*=”符号实现左外连接。
图9.18 左连接STUDENT表和COURSE表的查询结果
在WHERE子句,使用“*=”符号实现左外连接实现上例,代码如下。
SELECT S.SNO, SNAME, S.CNO, CNAME, CTEST, MARK运行结果如图9.19所示。
图9.19 使用“*=”符号实现的左外连接
说明 在Oracle数据库系统中,只需将“*=”替换成“+=”可以得到相同的结果。
2.右外连接
右外连接(RIGHT OUTER JOIN)告诉DBMS生成的结果表中,除了包括匹配行外,还包括JOIN关键字(FROM子句中)右边表的不匹配行。右外连接实际上可以表示为:
右外连接 = 内连接 + 右边表中失配的元组其中,缺少的左边表中的属性值用NULL表示。图9.20给出了典型的右外连接示意图。
图9.20 右外连接
实例12 右外连接STUDENT表和COURSE表
右外连接STUDENT表和COURSE表,查询所有同学的学号、姓名、课程代码、课程名称、考试时间和成绩信息。实例代码:
SELECT S.SNO, SNAME, S.CNO, CNAME, CTEST, MARK运行结果如图9.21所示。
图9.21 右外连接STUDENT表和COURSE表的查询结果
可见,最终得到的结果表中,除了包括两个表匹配的行(3~20行),还包括了右边表COURSE表中的不匹配行(1、2行),缺少的左边表,即STUDENT表中的属性值用NULL表示。
技巧 在SQL Server数据库系统中,可以在WHERE子句中使用“=*”符号实现右外连接。
实例13 在WHERE子句中使用“=*”符号实现右外连接
在WHERE子句,使用“=*”符号实现实例12,代码如下。
SELECT S.SNO, SNAME, S.CNO, CNAME, CTEST, MARK运行结果如图9.22所示。
图9.22 使用“=*”符号实现的右外连接
3.全外连接
全外连接,FULL OUTER JOIN,告诉DBMS生成的结果表中,除了包括匹配行外,还包括JOIN关键字(FROM子句中)左边表和右边表的不匹配行。全外连接实际上可以表示为:
全外连接 = 内连接 + 左边表中失配的元组 + 右边表中失配的元组。其中,缺少的左边表或者右边表中的属性值用NULL表示。图9.23给出了典型的全外连接示意图。
图9.23 全外连接
实例14 全外连接STUDENT表和COURSE表
全外连接STUDENT表和COURSE表,查询所有同学的学号、姓名、课程代码、课程名称、考试时间和成绩信息。实例代码:
SELECT S.SNO, SNAME, S.CNO, CNAME, CTEST, MARK运行结果如图9.24所示。
图9.24 全外连接STUDENT表和COURSE表的查询结果
可见,最终得到的结果表中,除了包括两个表匹配的行(5~22行),还包括了右边表COURSE表中的不匹配行(1、2行),缺少的左边表,即 STUDENT表中的属性值用NULL表示。以及左边表,STUDENT表中的不匹配行(3、4行),缺少的右边表,即COURSE表中的属性值用 NULL表示。
9.3.5 交叉连接(CROSS JOIN)
除了在FROM子句中使用逗号间隔连接的表外,SQL还支持另一种被称为交叉连接的操作,它们都返回被连接的两个表所有数据行的笛卡尔积,返回到的数据行数等于第一个表中符合查询条件的数据行数乘以第二个表中符合查询条件的数据行数。惟一的不同在于,交叉连接分开列名时,使用CROSS JOIN关键字而不是逗号。
实际上,下面两个表达式是完全等价的。
SELECT * FROM table1, table2图9.25给出了典型的交叉连接示意图。
图9.25 交叉连接
实例15 交叉连接STUDENT表和COURSE表
交叉连接STUDENT表和COURSE表,查询所有同学的学号、姓名、课程代码、课程名称、考试时间和成绩信息。实例代码:
SELECT SNO, SNAME, S.CNO, C.CNAME, CTEST, MARK运行结果如图9.26所示。
注意 在使用CROSS JOIN关键字交叉连接表时,因为生成的是两个表的笛卡尔积,因而不能使用ON关键字,只能在WHERE子句中定义搜索条件。
事实上,直接使用CROSS JOIN很少得到想要的结果,但是,正如实例所示,作为查询的第一步,DBMS通常在FROM子句中,对连接的表进行CROSS JOIN,然后过滤得到的中间表。
图9.26 交叉连接STUDENT表和COURSE表的查询结果