如今隨着各類數據庫框架的盛行,在提升效率的同時也讓咱們忽略了不少底層的鏈接過程,這篇文章是對 SQL 鏈接過程梳理,並涉及到了如今經常使用的 SQL 標準。sql
其實標準就是在不一樣的時間,制定的一些寫法或規範。數據庫
在編寫 SQL 語句前,須要先了解在不一樣版本的規範,由於隨着版本的變化,在具體編寫 SQL 時會有所不一樣。對於 SQL 來講,SQL92 和 SQL99 是最多見的兩個 SQL 標準,92 和 99 對應其提出的年份。除此以外,還存在 SQL8六、SQL8九、SQL200三、SQL200八、SQL2011,SQL2016等等。框架
但對咱們來講,SQL92 和 SQL99 是最經常使用的兩個標準,主要學習這兩個就能夠了。學習
爲了演示方便,如今數據庫中加入以下三張表:優化
每一個學生屬於一個班級,經過班級的人數來對應班級的類型。code
-- ---------------------------- DROP TABLE IF EXISTS `Student`; CREATE TABLE `Student` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(20) NOT NULL DEFAULT '', `birth` varchar(20) NOT NULL DEFAULT '', `sex` varchar(10) NOT NULL DEFAULT '', `class_id` int(11) NOT NULL COMMENT '班級ID', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of Student -- ---------------------------- INSERT INTO `Student` VALUES ('1', '胡一', '1994.1.1', '男', '1'); INSERT INTO `Student` VALUES ('3', '王阿', '1992.1.1', '女', '1'); INSERT INTO `Student` VALUES ('5', '王琦', '1993.1.2', '男', '1'); INSERT INTO `Student` VALUES ('7', '劉偉', '1998.2.2', '女', '1'); INSERT INTO `Student` VALUES ('11', '張使', '1994.1.1', '男', '3'); INSERT INTO `Student` VALUES ('13', '王阿', '1992.1.1', '女', '3'); INSERT INTO `Student` VALUES ('15', '夏琪', '1993.1.2', '男', '3'); INSERT INTO `Student` VALUES ('17', '劉表', '1998.2.2', '女', '3'); INSERT INTO `Student` VALUES ('19', '諸葛', '1994.1.1', '男', '3'); INSERT INTO `Student` VALUES ('21', '王前', '1992.1.1', '女', '3'); INSERT INTO `Student` VALUES ('23', '王意識', '1993.1.2', '男', '3'); INSERT INTO `Student` VALUES ('25', '劉等待', '1998.2.2', '女', '3'); INSERT INTO `Student` VALUES ('27', '胡是一', '1994.1.1', '男', '5'); INSERT INTO `Student` VALUES ('29', '王阿請', '1992.1.1', '女', '5'); INSERT INTO `Student` VALUES ('31', '王消息', '1993.1.2', '男', '5'); INSERT INTO `Student` VALUES ('33', '劉全', '1998.2.2', '女', '5'); INSERT INTO `Student` VALUES ('35', '胡愛', '1994.1.1', '男', '5'); INSERT INTO `Student` VALUES ('37', '王表', '1992.1.1', '女', '5'); INSERT INTO `Student` VALUES ('39', '王華', '1993.1.2', '男', '5'); INSERT INTO `Student` VALUES ('41', '劉偉以', '1998.2.2', '女', '5'); INSERT INTO `Student` VALUES ('43', '胡一彪', '1994.1.1', '男', '5'); INSERT INTO `Student` VALUES ('45', '王阿符', '1992.1.1', '女', '5'); INSERT INTO `Student` VALUES ('47', '王琦刪', '1993.1.2', '男', '5'); INSERT INTO `Student` VALUES ('49', '劉達達', '1998.2.2', '女', '5'); -- ---------------------------- -- Table structure for `Class` -- ---------------------------- DROP TABLE IF EXISTS `Class`; CREATE TABLE `Class` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(20) NOT NULL DEFAULT '', `number` int(11) NOT NULL DEFAULT '', `class_type_id` int(11) NOT NULL COMMENT '班級類型ID', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of Class -- ---------------------------- INSERT INTO `Class` VALUES ('1', '1年1班', 4, '1'); INSERT INTO `Class` VALUES ('3', '1年2班', 8, '3'); INSERT INTO `Class` VALUES ('5', '1年3班', 12, '5'); CREATE TABLE `ClassType`( `id` int(11) NOT NULL AUTO_INCREMENT, `name` VARCHAR(20) NOT NULL DEFAULT '', `minimum_number` int(11) NOT NULL DEFAULT '' COMMENT '最少的班級人數', `maximum_number` int(11) NOT NULL DEFAULT '' COMMENT '最多的班級人數', PRIMARY KEY(`id`) ); INSERT INTO `ClassType` VALUES ('1', '小班', '1', '4'); INSERT INTO `ClassType` VALUES ('3', '中班', '5', '8'); INSERT INTO `ClassType` VALUES ('5', '大班', '9', '12');
笛卡爾積是一個數學上的概念,表示若是存在 X,Y 兩個集合,則 X,Y 的笛卡爾積記爲 X * Y. 表示由 X,Y 組成有序對的全部狀況。對象
對應在 SQL 中,就是將兩張表中的每一行進行組合。並且在鏈接時,能夠沒有任何限制,可將沒有關聯關係的任意表進行鏈接。blog
這裏拿學生表和班級表舉例,在學生表中咱們插入了20名學生的數據,課程表中插入三個班級。則學生和班級的笛卡爾結果就是將兩表的每行數據一一組合,最後就是有 24 * 3 = 72 行的結果,以下圖所示。get
而且須要知道的是,下面學習的外鏈接,自鏈接,等值鏈接等都是在笛卡爾積的基礎上篩選獲得的。數學
對應的 SQL92 寫法爲:
select * from Student, Class;
等值鏈接就是將兩張表中都存在的列進行鏈接,具體來講就是 where 後面經過 = 進行篩選。
好比查詢 Student 和其所屬 Class 信息的關係:
SELECT * FROM Student as s, Class as c where s.class_id = c.id;
非等值鏈接就是將等值鏈接中的等號換成其餘的過濾條件。
好比這裏查詢每一個班級的信息以及所屬的班級類別。
SELECT * FROM Class as c, ClassType t where c.number between t.minimum_number and maximum_number;
對於 SQL92 的外鏈接來講,在鏈接時會將兩張表分爲主表和從表,主表顯示全部的數據,從表顯示匹配到的數據,沒有匹配到的則顯示 None. 用 +
表示從表的位置。
左外鏈接:左表是主表,右表時從表。
SELECT * FROM Student as s , Class as c where s.class_id = c.id(+);
右外鏈接:左表是從表,右表時主表。
SELECT * FROM Class as c, Student as s where c.id = s.class_id(+);
注意 SQL92 中並無全外鏈接。
自鏈接通常用於鏈接自己這張表,因爲常見的 DBMS 都會對自鏈接作一些優化,因此通常在子查詢和自鏈接的狀況下都使用自鏈接。
好比想要查詢比1年1班人數多的班級:
子查詢:
SELECT * FROM Class WHERE number > (SELECT number FROM Class WHERE name="1年1班");
自鏈接:
SELECT c2.* FROM Class c1, Class c2 WHERE c1.number < c2.number and c1.name = "1年1班";
SELECT * FROM Student CROSS JOIN Class;
還能夠對多張表進行交叉鏈接,好比鏈接 Student,Class,ClassType 三張表,結果爲 24 * 3 * 3 = 216 條。
至關於嵌套了三層 for 循環。
其實就是 SQL92 中的等值鏈接,只不過鏈接的對象是具備相同列名,而且值也相同的內容。
SELECT * FROM Student NATURAL JOIN CLASS;
SELECT * FROM Student as s, Class as c where s.id = c.id;
若是想用 NATURAL JOIN
時,建議爲兩表設置相同的列名,好比 Student 表中的班級列爲 class_id
, 則在 Class 表中,id 也應改成 class_id
. 這樣鏈接更合理一些。
若是你們嘗試,天然鏈接的話,會發現查出來的結果集爲空,不要奇怪,下面說一下緣由:
這是由於,NATURAL JOIN 會自動鏈接兩張表中相同的列名,而對於 Student 和 Class 兩張表來講,id 和 name 在這兩張表都是相同的,因此既知足 id 又知足 name 的行是不存在的。
至關於 SQL 變成了這樣
SELECT * FROM Student as s, Class as c where s.id = c.id and s.name = c.name;
ON 鏈接其實對了 SQL92 中的等值鏈接和非等值鏈接:
等值鏈接:
SELECT * FROM Student as s JOIN Class as c ON s.class_id = c.id; or SELECT * FROM Student as s INNER JOIN Class as c ON s.class_id = c.id;
非等值鏈接:
SELECT * FROM Class as c JOIN ClassType t ON c.number between t.minimum_number and maximum_number;
和 NATURAL JOIN 很像,能夠手動指定具備相同列名的列進行鏈接:
SELECT * FROM Student JOIN Class USING(id);
這時就解決了以前列存在重名,沒法鏈接的狀況。
左外鏈接: 左表是主表,右表時從表。
SELECT * FROM Student as s LEFT JOIN Class as c on s.class_id = c.id; OR SELECT * FROM Student as s LEFT OUTER JOIN Class as c on s.class_id = c.id;
右外鏈接:左表是從表,右表時主表。
SELECT * FROM Student as s RIGHT JOIN Class as c on s.class_id = c.id; OR SELECT * FROM Student as s RIGHT OUTER JOIN Class as c on s.class_id = c.id;
全外鏈接: 左外鏈接 + 右外的鏈接的合集
SELECT * FROM Student as s FULL JOIN Class as c ON s.class_id = c.id;
MySQL 中沒有全外鏈接的概念。
自鏈接:
SELECT c2.* FROM Class c1 JOIN Class c2 ON c1.number < c2.number and c1.name = "1年1班";
SQL92 中的等值鏈接(內鏈接),非等值鏈接,自鏈接對應了 SQL99 的 ON 鏈接,用於篩選知足鏈接條件的數據行。
SQL92 的笛卡爾積鏈接,對應了 SQL99 的交叉鏈接。
SQL92 中的外鏈接並不包含全外鏈接,而 SQL99 支持,而且將 SQL92 中 WHERE 換爲 SQL99 的 ON. 這樣的好處能夠更清晰的表達鏈接表的過程,更直觀。
SELECT ... FROM table1 JOIN table2 ON filter_condition JOIN table3 ON filter_condition
SQL99 多了天然鏈接和 USING 鏈接的過程,二者的區別是是否須要顯式的指定列名。
咱們知道,在 SQL 中,按照年份劃分了不一樣的標準,其中最爲經常使用的是 SQL-92 和 SQL-99 兩個標準。
接着,對比了 92 和 99 二者的不一樣,發現 99 的標準在鏈接時,更加符合邏輯而且更加直觀。
最後,上一張各類鏈接的示意圖, 方便梳理複習: