SQL语言 - 自连接

自连接意思就是表与其自身进行连接。虽然自连接并不是必须的,可以通过其他方式来完成,但是在某些情况下,使用自连接就比较方便。比如一张员工信息表,这张表上有该员工的基本信息,还有指明了他的上司的ID号。但是同时他的上司也是员工,在这张表上也有他的信息。如果我们需要显示出所有员工的姓名和他上司的姓名,虽然我们可以通过其他方式,比如使用子查询来完成这一任务,但是无疑使用自连接可能是最好的办法。比如下面这张表:

员工号码员工姓名上司号码
001张三003
002李四005
003王五009
004赵六003
005吴七010
006周八005
007胡九 003
008陈十010
009杨二010
010刘一 
          

现在我们要查询出每个员工的姓名以及他上司的姓名,如果不使用自连接那么我们就可以用下面的方式来完成该查询
select name 员工姓名
,(select name from employee mg where ep.managerid = mg.id) 上司姓名
from employee ep

查询结果:
 

员工姓名上司姓名
张三王五
李四吴七
王五杨二 
赵六王五
吴七刘一
周八吴七
胡九王五
陈十刘一
杨二刘一
刘一 

                
在这个查询语句中,使用了一个子查询来完成对上司姓名的查询。
如果使用自连接。那么结构会感觉清晰许多,如:
select ep.name 员工姓名,mg.name 上司姓名
from EMPLOYEE ep
LEFT JOIN EMPLOYEE mg ON ep.managerid = mg.id
这里除了使用自连接外还使用了左外连接,因为‘刘一’这个员工是所有人的上司,并且他没有其他的上司,也就是说他是老总了。如果用内连接就会把这行记录过滤掉,因为没有和他匹配的上司姓名。使用左外连接就可以避免这一情况。

查询结果:
 

员工姓名上司姓名
胡九王五
赵六王五
张三 王五
周八吴七
李四 吴七
王五杨二
杨二刘一
陈十刘一
吴七刘一
刘一 

               
查询结果都是一样的,只是最后显示出来的顺序不一样。

下面进入自连接的相关练习。
相关练习的数据库请参看:http://www.sqlzoo.cn/buses.htm
练习题地址:http://www.sqlzoo.cn/6.htm
练习题答案及分析:
1a. 显示数据库中包含多少车站.
SELECT COUNT(*) FROM stops

1b. 找出站名为'Craiglockhart'的id 号
SELECT id FROM stops WHERE name='Craiglockhart'

1c. 给出 'LRT'公司经营的'4'号线路的所有车站的id(站号)和name(站名)
SELECT id, name FROM stops, route
  WHERE id=stop
    AND company='LRT'
    AND num='4'

2a. 请看一下已经给出的查询,它将列出所有公交线路经过车站London Road (149)或Craiglockhart (53)的次数. 修改一下该查询,使得该查询仅列出两次经过这些车站的两条线路.
SELECT company, num, COUNT(*)
FROM route WHERE stop=149 OR stop=53
GROUP BY company, num
修改后:
SELECT company, num, COUNT(*)
FROM route WHERE stop=149 OR stop=53
GROUP BY company, num
HAVING COUNT(*)=2

2b. 执行下面的self join(自连接)查询,可以发现 b.stop 给出了所有从Craiglockhart(stop=53)出发可到达的站点. 请调整一下该查询,让它给从Craiglockhart(stop=53)到London Road(stop=149)的线路.
修改后:
SELECT a.company, a.num, a.stop, b.stop
FROM route a JOIN route b ON
  (a.company=b.company AND a.num=b.num)
WHERE a.stop = 149 AND b.stop=53
上面这道题就是使用了自连接,在使用自连接时,一定要给表加上别名,这样才能区分两张表。我们可以将自连接看成是两张不同的表,而其他连接的方式和多表连接没有什么不同,这样才能更容易的理解自连接。

2c. 下面的查询和上例中的比较类似.只是通过两次连接stops表,让我们可以通过站名而不是站号来查询公交线路.请调整一下该查询,让它可以显示'Craiglockhart'和'London Road'间的公交线路. 你也可以试试显示'Fairmilehead' 和 'Tollcross'间的公交线路.
修改后:
SELECT a.company, a.num, stopa.name, stopb.name
FROM route a JOIN route b ON
  (a.company=b.company AND a.num=b.num)
  JOIN stops stopa ON (a.stop=stopa.id)
  JOIN stops stopb ON (b.stop=stopb.id)
WHERE stopa.name='Craiglockhart'
  AND stopb.name='London Road'

3a. 给出连接车站号为115和137公交线路.
SELECT R1.company, R1.num
  FROM route R1, route R2
  WHERE R1.num=R2.num AND R1.company=R2.company
    AND R1.stop=115 AND R2.stop=137

3b. 给出连接车站 'Craiglockhart' and 'Tollcross'的公交线路.
SELECT R1.company, R1.num
  FROM route R1, route R2, stops S1, stops S2
  WHERE R1.num=R2.num AND R1.company=R2.company
    AND R1.stop=S1.id AND R2.stop=S2.id
    AND S1.name='Craiglockhart'
    AND S2.name='Tollcross'

3c. 给出可以从'Craiglockhart' 车站乘坐一辆汽车就能到达的车站.显示的结果包含到达车站号,车站名,公交线路的公司和公交线路号.
SELECT S2.id, S2.name, R2.company, R2.num
  FROM stops S1, stops S2, route R1, route R2
  WHERE S1.name='Craiglockhart'
    AND S1.id=R1.stop
    AND R1.company=R2.company AND R1.num=R2.num
    AND R2.stop=S2.id
 
3d. 给出从Sighthill 到 Craiglockhart的所有可能的交通线路.
这道题我是始终没做对。我找到了它的标准答案,贴上去还是有问题。不知道这道题是不是本身就有问题。希望哪位高人能帮我解决这个疑惑~下面贴出它的标准答案:
SELECT a.name Start_At, b.num FirstBus, b.company FBC,
       e.name Change_At, f.num SecondBus, f.company SBC,
       g.name Arive_At
 FROM  stops a, route b,
       stops c, route d,
       stops e, route f,
       stops g, route h
WHERE  a.id = b.stop                
  AND  c.id = d.stop
  AND  e.id = f.stop
  AND  g.id = h.stop
 
  AND  b.num = d.num
  AND  b.company = d.company  

  AND  f.num = h.num
  AND  f.company = h.company  
  AND  c.name = e.name

  AND  a.name = 'Craiglockhart'
  AND  g.name = 'Sighthill'

  AND d.pos > b.pos
  AND h.pos > f.pos
看起来有点恐怖吧,反正我是没辙了。。。

总结:其实SQL语言本身并不难,难点在于对数据库的理解上,因此我还是认为,学习数据库应该把重点放在数据库本身的设计上。

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值