在我叙述JOIN的用法前,我先引用数据库设计中最常见的范式资料。
第三范式(3NF):如果关系模式R(U,F)中的所有非主属性对任何候选关键字都不存在传递信赖,则称关系R是属于第三范式的。
例:如S1(SNO,SNAME,DNO,DNAME,LOCATION) 各属性分别代表学号,姓名,所在系,系名称,系地址。
关键字SNO决定各个属性。由于是单个关键字,没有部分依赖的问题,肯定是2NF。但这关系肯定有大量的冗余,有关学生所在的几个属性DNO,DNAME,LOCATION将重复存储,插入,删除和修改时也将产生类似以上例的情况。
原因:关系中存在传递依赖造成的。由于SNAME和DNO是依赖SNO,而DNAME和LOCATION是依赖DNO的,即通过一个学号可以知道该学生的姓名以及他所在系代码,但无法由学号知道系地址,学号和系地址间是通过学号所对应的学生的所在系关联的, 因此关键字 SNO 对 LOCATION 函数决定是通过传递依赖 DNO -> LOCATION 实现的。也就是说,SNO不直接决定非主属性LOCATION。
解决目地:每个关系模式中不能留有传递依赖。
解决方法:分为两个关系 S(SNO,SNAME,DNO),D(DNO,DNAME,LOCATION)
注意:关系S中不能没有外关键字DNO。否则两个关系之间失去联系。
在数据库的设计过程中常常按照第三范式来设计数据库,当然在有些场合为优化数据库的性能而增加了相关冗余字段以使表的结构不符合3NF,在多数场合中,没有一张表能完整的发挥客户所需要的结果集。这样就需要通过联接多张在逻辑上存在依赖关系的表,选择你所需要的数据。
在使用JOIN前,必须明白是通过联接,根据各个表之间的逻辑关系从相关表中检索数据。通过SQL Server自带帮助文件,可以清楚的知道:可在 FROM 或 WHERE 子句中指定联接。
下例使用WHERE子句进行表之间的
SELECT A.SYMBOL,A.SNAME,B.TDATE,B.CLOSE
FROM SECURITYCODE A,DAYQUOTE B
WHERE A.SYMBOL =B.SYMBOL
AND B.TDATE >= A.LISTDATE
AND A.SYMBOL LIKE '600%'
在上例中联接的表A与表B通过A.SYMBOL =B.SYMBOL这个条件联接,筛选条件为B.TDATE不小于A. LISTDATE。
在WHERE子句中指定联接,对于较简单的联接,使用这种方式可能较方便,但综合来说,不推荐使用该语法联接表。
拿上面的例子来详细说,表SECURITYCODE中主要存放证券代码的基本信息,表中的SYMBOL代表股票代码,SNAME代表股票名称,LISTDATE代表上市日期;表DAYQUOTE中主要存放股票的每日行情。SYMBOL代表股票代码,TDATE代表交易日期, CLOSE代表收盘价。
我现在的取值逻辑是:取出股票代码以600打头的股票自上市日期以来的所有交易日的收盘价。将SECURITYCODE与DAYQUOTE通过SYMBOL联接。
SELECT A.SYMBOL,A.SNAME,B.TDATE,B. CLOSE
FROM SECURITYCODE A
JOIN DAYQUOTE B
ON A.SYMBOL =B.SYMBOL
WHERE B.TDATE >= A.LISTDATE
AND A.SYMBOL LIKE '600%'
ORDER BY A.SYMBOL,B.TDATE
对于使用FROM子句方式联接表,可以很清楚的看出表之间的联接条件。就可读性以及后续的可修改性与WHERE子句相比有较大的优势。
下面就联接的方式引用帮助文件中的具体介绍,联接可以分为以下几种:
内联接(典型的联接运算,使用像 = 或 <> 之类的比较运算符)。包括相等联接和自然联接。
内联接使用比较运算符根据每个表共有的列的值匹配两个表中的行。
在 SQL-92 标准中,内联接可在 FROM 或 WHERE 子句中指定。这是 WHERE 子句中唯一一种 SQL-92 支持的联接类型。WHERE 子句中指定的内联接称为旧式内联接。
内联接一般常见写法:
SELECT A.COLUMN1,[A.COLUMN2],B.COLUMN1,[B.COLUMN2]
FROM TABLE1 A
[INNER] JOIN TABLE2 B
ON A.COLUMN0 = B.COLUMN0
在查询分析器中使用INNER JOIN时常常省略INNER。
外联接可以是左向外联接、右向外联接或完整外部联接。
在 FROM 子句中指定外联接时,可以由下列几组关键字中的一组指定:
LEFT JOIN 或 LEFT OUTER JOIN
左向外联接的结果集包括 LEFT OUTER 子句中指定的左表的所有行,而不仅仅是联接列所匹配的行。如果左表的某行在右表中没有匹配行,则在相关联的结果集行中右表的所有选择列表列均为空值。
RIGHT JOIN 或 RIGHT OUTER JOIN
右向外联接是左向外联接的反向联接。将返回右表的所有行。如果右表的某行在左表中没有匹配行,则将为左表返回空值。
FULL JOIN 或 FULL OUTER JOIN
完整外部联接返回左表和右表中的所有行。当某行在另一个表中没有匹配行时,则另一个表的选择列表列包含空值。如果表之间有匹配行,则整个结果集行包含基表的数据值。
仅当至少有一个同属于两表的行符合联接条件时,内联接才返回行。内联接消除与另一个表中的任何行不匹配的行。而外联接会返回 FROM 子句中提到的至少一个表或视图的所有行,只要这些行符合任何 WHERE 或 HAVING 搜索条件。将检索通过左向外联接引用的左表的所有行,以及通过右向外联接引用的右表的所有行。完整外部联接中两个表的所有行都将返回。
外联接的中常见的是LEFT JOIN,将LEFT JOIN用熟已经可以解决大半问题了。
外联接的一般写法:
SELECT A.COLUMN1,[A.COLUMN2],B.COLUMN1,[B.COLUMN2]
FROM TABLE1 A
LEFT|RIGHT|FULL [OUTER] JOIN TABLE2 B
ON A.COLUMN0 = B.COLUMN0
在查询分析器中使用OUTER JOIN时常常省略OUTER。LEFT和RIGHT只是方向问题,在特定场合下,FULL OUTER JOIN 相当于LEFT OUTER JOIN 和 RIGHT OUTER JOIN的消除重复行的合集。
交叉联接返回左表中的所有行,左表中的每一行与右表中的所有行组合。交叉联接也称作笛卡尔积。
没有 WHERE 子句的交叉联接将产生联接所涉及的表的笛卡尔积。第一个表的行数乘以第二个表的行数等于笛卡尔积结果集的大小。也就是说在没有WHERE子句的情况下,若表A有3行记录,表B有6行记录::
SELECT A.*,B.* FROM 表A CROSS JOIN 表B
那以上语句会返回18行记录。