order by
如果存在多個排序字段,在前一個不能比較出結果後,後邊的才起作用
可以分別指明是升序還是降序:asc(ascending) desc(descending)
用法:
[ORDER BY {col_name | expr | position} [ASC | DESC] , ...]
注意:
- 是對檢索出來的字段進行排序,一定要在where之後
- 如果是分組,則應該使用對分組字段進行排序的groupby語法。
mysql> select * from teacher_class where 1 order by days;
+----+--------+--------+---------+------+------+------------+------------+
| id | t_name | gender | c_name | room | days | begin_date | end_date |
+----+--------+--------+---------+------+------+------------+------------+
| 6 | 韓非 | secret | php0115 | 207 | 15 | 2013-03-27 | 2013-04-18 |
| 2 | 韓信 | male | php0228 | 106 | 18 | 2013-02-28 | 2013-03-30 |
| 4 | 李白 | male | php0115 | 207 | 20 | 2013-02-22 | 2013-03-25 |
| 1 | 韓信 | male | php0115 | 207 | 21 | 2013-01-15 | 2013-02-20 |
| 5 | 李白 | male | php0228 | 204 | 21 | 2013-03-31 | 2013-04-29 |
| 3 | 韓信 | male | php0331 | 102 | 24 | 2013-03-31 | 2013-05-05 |
+----+--------+--------+---------+------+------+------------+------------+
6 rows in set (0.00 sec)
mysql> select * from teacher_class where 1 order by days desc;
+----+--------+--------+---------+------+------+------------+------------+
| id | t_name | gender | c_name | room | days | begin_date | end_date |
+----+--------+--------+---------+------+------+------------+------------+
| 3 | 韓信 | male | php0331 | 102 | 24 | 2013-03-31 | 2013-05-05 |
| 1 | 韓信 | male | php0115 | 207 | 21 | 2013-01-15 | 2013-02-20 |
| 5 | 李白 | male | php0228 | 204 | 21 | 2013-03-31 | 2013-04-29 |
| 4 | 李白 | male | php0115 | 207 | 20 | 2013-02-22 | 2013-03-25 |
| 2 | 韓信 | male | php0228 | 106 | 18 | 2013-02-28 | 2013-03-30 |
| 6 | 韓非 | secret | php0115 | 207 | 15 | 2013-03-27 | 2013-04-18 |
+----+--------+--------+---------+------+------+------------+------------+
6 rows in set (0.00 sec)
上述代碼可以看出,默認是升序的。mysql> select t_name, days from teacher_class where 1 group by t_name order by days desc;
+--------+------+
| t_name | days |
+--------+------+
| 韓信 | 21 |
| 李白 | 20 |
| 韓非 | 15 |
+--------+------+
3 rows in set (0.00 sec)
order by對分組的數據進行排序是無效的,必須經過group by內部的排序纔有效!mysql> select * from
-> (select t_name as name, sum(days) as day from teacher_class group by t_name) as tb
-> order by day;
+------+------+
| name | day |
+------+------+
| 韓非 | 15 |
| 李白 | 41 |
| 韓信 | 63 |
+------+------+
3 rows in set (0.00 sec)
mysql> select * from
-> (select t_name as name, sum(days) as day from teacher_class group by t_name) as tb
-> order by day desc;
+------+------+
| name | day |
+------+------+
| 韓信 | 63 |
| 李白 | 41 |
| 韓非 | 15 |
+------+------+
3 rows in set (0.00 sec)
limit
用法:
[LIMIT {[offset,] row_count | row_count OFFSET offset}]
- Offset 偏移量,從0開始。可以省略,默認爲0.(也就是下邊索引是從0開始的)
- Row_count 總記錄數,如果數量大於,餘下的記錄數,則獲取所有餘下的即可:
表示從offset索引位置開始獲取row_count條記錄。
可以省略offset,默認爲0. limit row_count == limit 0, row_count;
mysql> select * from teacher_class limit 3,4;
+----+--------+--------+---------+------+------+------------+------------+
| id | t_name | gender | c_name | room | days | begin_date | end_date |
+----+--------+--------+---------+------+------+------------+------------+
| 4 | 李白 | male | php0115 | 207 | 20 | 2013-02-22 | 2013-03-25 |
| 5 | 李白 | male | php0228 | 204 | 21 | 2013-03-31 | 2013-04-29 |
| 6 | 韓非 | secret | php0115 | 207 | 15 | 2013-03-27 | 2013-04-18 |
+----+--------+--------+---------+------+------+------------+------------+
3 rows in set (0.00 sec)
從索引行第三行開始,截取四行數據,也就是截取3,4,5,6行數據(索引從0開始)。mysql> select * from teacher_class limit 5;
+----+--------+--------+---------+------+------+------------+------------+
| id | t_name | gender | c_name | room | days | begin_date | end_date |
+----+--------+--------+---------+------+------+------------+------------+
| 1 | 韓信 | male | php0115 | 207 | 21 | 2013-01-15 | 2013-02-20 |
| 2 | 韓信 | male | php0228 | 106 | 18 | 2013-02-28 | 2013-03-30 |
| 3 | 韓信 | male | php0331 | 102 | 24 | 2013-03-31 | 2013-05-05 |
| 4 | 李白 | male | php0115 | 207 | 20 | 2013-02-22 | 2013-03-25 |
| 5 | 李白 | male | php0228 | 204 | 21 | 2013-03-31 | 2013-04-29 |
+----+--------+--------+---------+------+------+------------+------------+
5 rows in set (0.00 sec)
從第0行開始,截取前五行數據;mysql> select * from teacher_class limit 5, 100;
+----+--------+--------+---------+------+------+------------+------------+
| id | t_name | gender | c_name | room | days | begin_date | end_date |
+----+--------+--------+---------+------+------+------------+------------+
| 6 | 韓非 | secret | php0115 | 207 | 15 | 2013-03-27 | 2013-04-18 |
+----+--------+--------+---------+------+------+------------+------------+
1 row in set (0.00 sec)
當行數大於剩下的所有行數時,獲取所有剩下的行數。mysql> select * from teacher_class order by days desc limit 1;
+----+--------+--------+---------+------+------+------------+------------+
| id | t_name | gender | c_name | room | days | begin_date | end_date |
+----+--------+--------+---------+------+------+------------+------------+
| 3 | 韓信 | male | php0331 | 102 | 24 | 2013-03-31 | 2013-05-05 |
+----+--------+--------+---------+------+------+------------+------------+
1 row in set (0.00 sec)
獲取天數最多的一行數據。distinct
所謂重複的記錄,指的是字段值都相同的記錄,而不是部分字段相同的記錄。
mysql> select * from teacher_class;
+----+--------+--------+---------+------+------+------------+------------+
| id | t_name | gender | c_name | room | days | begin_date | end_date |
+----+--------+--------+---------+------+------+------------+------------+
| 1 | 韓信 | male | php0115 | 207 | 21 | 2013-01-15 | 2013-02-20 |
| 2 | 韓信 | male | php0228 | 106 | 18 | 2013-02-28 | 2013-03-30 |
| 3 | 韓信 | male | php0331 | 102 | 24 | 2013-03-31 | 2013-05-05 |
| 4 | 李白 | male | php0115 | 207 | 20 | 2013-02-22 | 2013-03-25 |
| 5 | 李白 | male | php0228 | 204 | 21 | 2013-03-31 | 2013-04-29 |
| 6 | 韓非 | secret | php0115 | 207 | 15 | 2013-03-27 | 2013-04-18 |
+----+--------+--------+---------+------+------+------------+------------+
mysql> select distinct t_name from teacher_class;
+--------+
| t_name |
+--------+
| 韓信 |
| 李白 |
| 韓非 |
+--------+
3 rows in set (0.00 sec)
所有名字都不相同的記錄。mysql> select distinct t_name,gender from teacher_class;
+--------+--------+
| t_name | gender |
+--------+--------+
| 韓信 | male |
| 李白 | male |
| 韓非 | secret |
+--------+--------+
3 rows in set (0.00 sec)
名字和型別都不相同的記錄。all
mysql> select all t_name from teacher_class;
+--------+
| t_name |
+--------+
| 韓信 |
| 韓信 |
| 韓信 |
| 李白 |
| 李白 |
| 韓非 |
+--------+
6 rows in set (0.00 sec)
其實默認的就是all操作,所以加不加all都是一樣的。
mysql> select t_name from teacher_class;
+--------+
| t_name |
+--------+
| 韓信 |
| 韓信 |
| 韓信 |
| 李白 |
| 李白 |
| 韓非 |
+--------+
6 rows in set (0.00 sec)
union
用法:
SELECT ...UNION [ALL | DISTINCT]SELECT ...[UNION [ALL | DISTINCT]SELECT ...]
獲得每一個班級內代課最多的講師。
mysql> select t_name, max(days), c_name from teacher_class group by c_name;
+--------+-----------+---------+
| t_name | max(days) | c_name |
+--------+-----------+---------+
| 韓信 | 21 | php0115 |
| 韓信 | 21 | php0228 |
| 韓信 | 24 | php0331 |
+--------+-----------+---------+
注意:
數據列是根據列而不是根據名字進行匹配的。
在第一個SELECT語句中被使用的列名稱被用於結果的列名稱
默認情況下,會去除重複的數據行,可以使用union all保留重複的數據行。
如要對union的結果作爲整體進行排序或limit,(最好對單個地SELECT語句加圓括號),在後邊增加order by 或limit。order by引用的數據列來自第一個select。
分別排序,再聯合,則需要用括號將各select語句括起來,且order by只能在limit 出現時纔有效。
獲取php0115班和php0228班數代課天數最多的兩個老師的記錄:
mysql> (select * from teacher_class where c_name='php0115' order by days desc limit 1)
-> union
-> (select * from teacher_class where c_name='php0228' order by days desc limit 1);
+----+--------+--------+---------+------+------+------------+------------+
| id | t_name | gender | c_name | room | days | begin_date | end_date |
+----+--------+--------+---------+------+------+------------+------------+
| 1 | 韓信 | male | php0115 | 207 | 21 | 2013-01-15 | 2013-02-20 |
| 5 | 李白 | male | php0228 | 204 | 21 | 2013-03-31 | 2013-04-29 |
+----+--------+--------+---------+------+------+------------+------------+
2 rows in set (0.01 sec)
union all
注意,如果union 的結果存在重複的記錄,那麼會消除重複.可以通過 union選項 all 達到目的。
mysql> (select t_name, days, c_name from teacher_class where c_name='php0115' order by days asc)
-> union
-> (select t_name, days, c_name from teacher_class where c_name='php0228' order by days desc);
+--------+------+---------+
| t_name | days | c_name |
+--------+------+---------+
| 韓信 | 21 | php0115 |
| 李白 | 20 | php0115 |
| 韓非 | 15 | php0115 |
| 韓信 | 18 | php0228 |
| 李白 | 21 | php0228 |
+--------+------+---------+
5 rows in set (0.00 sec)
mysql> (select t_name, days, c_name from teacher_class where c_name='php0115' order by days asc)
-> union all
-> (select t_name, days, c_name from teacher_class where c_name='php0228' order by days desc);
+--------+------+---------+
| t_name | days | c_name |
+--------+------+---------+
| 韓信 | 21 | php0115 |
| 李白 | 20 | php0115 |
| 韓非 | 15 | php0115 |
| 韓信 | 21 | php0115 |
| 韓信 | 18 | php0228 |
| 李白 | 21 | php0228 |
+--------+------+---------+
6 rows in set (0.00 sec)
mysql> (select t_name, days, c_name from teacher_class where c_name='php0115')
-> union all
-> (select t_name, days, c_name from teacher_class where c_name='php0228') order by days desc;
+--------+------+---------+
| t_name | days | c_name |
+--------+------+---------+
| 韓信 | 21 | php0115 |
| 李白 | 21 | php0228 |
| 韓信 | 21 | php0115 |
| 李白 | 20 | php0115 |
| 韓信 | 18 | php0228 |
| 韓非 | 15 | php0115 |
+--------+------+---------+
6 rows in set (0.00 sec)
在合併的記錄最後進行統一降序排序。mysql> (select t_name, days, c_name from teacher_class where c_name='php0115')
-> union all
-> (select days, t_name, c_name from teacher_class where c_name='php0228') order by days
-> ;
+--------+------+---------+
| t_name | days | c_name |
+--------+------+---------+
| 韓非 | 15 | php0115 |
| 李白 | 20 | php0115 |
| 韓信 | 21 | php0115 |
| 韓信 | 21 | php0115 |
| 21 | 李白 | php0228 |
| 18 | 韓信 | php0228 |
+--------+------+---------+
6 rows in set (0.00 sec)
發生了數據類型的轉換!subquery子查詢
分類:
一個子查詢會返回一個標量(單一值)、一個行、一個列或一個表(一行或多行及一列或多列)。
這些子查詢被稱爲標量、列、行和表子查詢。
根據子查詢select 出現的的位置不同
Where型子查詢,from型子查詢
使用:
子查詢和外部查詢可以是任意表,不要求是同表。
語法:
子查詢必須位於小括號中。
子查詢外部語句可以是:SELECT, INSERT, UPDATE, DELETE, SET或DO
不能在子查詢時修改。
列子查詢:返回值是一列值。
行子查詢:返回一個行。
表子查詢:返回多個行。
標量子查詢
標量,語法:
non_subquery_operand comparison_operator (subquery)
可以使用的運算符:
= > < >= <= <>
mysql> insert into teacher_class values
-> (null, '李寧', 'male', 'php0331', '102', 24, '2013-03-31', '2013-05-05');
Query OK, 1 row affected (0.03 sec)
mysql> select * from teacher_class;
+----+--------+--------+---------+------+------+------------+------------+
| id | t_name | gender | c_name | room | days | begin_date | end_date |
+----+--------+--------+---------+------+------+------------+------------+
| 1 | 韓信 | male | php0115 | 207 | 21 | 2013-01-15 | 2013-02-20 |
| 2 | 韓信 | male | php0228 | 106 | 18 | 2013-02-28 | 2013-03-30 |
| 3 | 韓信 | male | php0331 | 102 | 24 | 2013-03-31 | 2013-05-05 |
| 4 | 李白 | male | php0115 | 207 | 20 | 2013-02-22 | 2013-03-25 |
| 5 | 李白 | male | php0228 | 204 | 21 | 2013-03-31 | 2013-04-29 |
| 6 | 韓非 | secret | php0115 | 207 | 15 | 2013-03-27 | 2013-04-18 |
| 7 | 韓信 | male | php0115 | 207 | 21 | 2013-01-15 | 2013-02-20 |
| 8 | 李寧 | male | php0331 | 102 | 24 | 2013-03-31 | 2013-05-05 |
+----+--------+--------+---------+------+------+------------+------------+
8 rows in set (0.00 sec)
如何獲得,代課最多的老師呢?(如果有多個老師代課天數一致,都是最大值如何處理呢?)
mysql> select * from teacher_class order by days desc limit 1;
+----+--------+--------+---------+------+------+------------+------------+
| id | t_name | gender | c_name | room | days | begin_date | end_date |
+----+--------+--------+---------+------+------+------------+------------+
| 3 | 韓信 | male | php0331 | 102 | 24 | 2013-03-31 | 2013-05-05 |
+----+--------+--------+---------+------+------+------------+------------+
1 row in set (0.00 sec)
Select max(days) from teacher_class;
再 判讀哪個老師的代課天數和最大值是一樣的。mysql允許將上面的查詢結果,作爲一個值來使用。
Var1 = Select max(days) from teacher_class;保存起來
Select t_name, gender from teacher_class where days = var1;
mysql> select * from teacher_class where days=(select max(days) from teacher_class);
+----+--------+--------+---------+------+------+------------+------------+
| id | t_name | gender | c_name | room | days | begin_date | end_date |
+----+--------+--------+---------+------+------+------------+------------+
| 3 | 韓信 | male | php0331 | 102 | 24 | 2013-03-31 | 2013-05-05 |
| 8 | 李寧 | male | php0331 | 102 | 24 | 2013-03-31 | 2013-05-05 |
+----+--------+--------+---------+------+------+------------+------------+
2 rows in set (0.02 sec)
列子查詢
mysql> select * from teacher_class where t_name in (select t_name from teacher_class where c_name = 'php0228');
+----+--------+--------+---------+------+------+------------+------------+
| id | t_name | gender | c_name | room | days | begin_date | end_date |
+----+--------+--------+---------+------+------+------------+------------+
| 1 | 韓信 | male | php0115 | 207 | 21 | 2013-01-15 | 2013-02-20 |
| 2 | 韓信 | male | php0228 | 106 | 18 | 2013-02-28 | 2013-03-30 |
| 3 | 韓信 | male | php0331 | 102 | 24 | 2013-03-31 | 2013-05-05 |
| 4 | 李白 | male | php0115 | 207 | 20 | 2013-02-22 | 2013-03-25 |
| 5 | 李白 | male | php0228 | 204 | 21 | 2013-03-31 | 2013-04-29 |
| 7 | 韓信 | male | php0115 | 207 | 21 | 2013-01-15 | 2013-02-20 |
+----+--------+--------+---------+------+------+------------+------------+
6 rows in set (0.00 sec)
首先進行子查詢找到班級名爲php0228的授課老師名字,然後在表中查詢名字爲這兩個老師的所有的表記錄。mysql> select * from teacher_class where t_name=any (select t_name from teacher_class where c_name = 'php0228');
這句話和上句話返回結果是一樣的。集合運算符:
列:
operand IN|NOT IN (subquery)
滿足數據中的任意一個,返回真。都不滿足返回假。
operand comparison_operator ANY (subquery)
operand comparison_operator SOME (subquery)
數據中的任何一個。=Any相當於in。而!=any 不是 not in。 意義是隻要不等於其中任何一個即可。
Some 和 any是別名。因爲 英語人,不能理解 not equal any(!=any) 的含義,not equal some(!=some)英語人知道。
operand comparison_operator ALL (subquery)
全部匹配,!=all爲not in;
行:
單行
(字段1,字段2) = (select 字段1,字段2 from 表 limit 1)
多行(表) in
(字段1,字段2) = (select 字段1, 字段2 from 表 );
與某老師具有同樣代課經歷的所有講師(同一個班,同一個教室)
行子查詢
mysql> select * from teacher_class;
+----+--------+--------+---------+------+------+------------+------------+
| id | t_name | gender | c_name | room | days | begin_date | end_date |
+----+--------+--------+---------+------+------+------------+------------+
| 1 | 韓信 | male | php0115 | 207 | 21 | 2013-01-15 | 2013-02-20 |
| 2 | 韓信 | male | php0228 | 106 | 18 | 2013-02-28 | 2013-03-30 |
| 3 | 韓信 | male | php0331 | 102 | 24 | 2013-03-31 | 2013-05-05 |
| 4 | 李白 | male | php0115 | 207 | 20 | 2013-02-22 | 2013-03-25 |
| 5 | 李白 | male | php0228 | 204 | 21 | 2013-03-31 | 2013-04-29 |
| 6 | 韓非 | secret | php0115 | 207 | 15 | 2013-03-27 | 2013-04-18 |
| 7 | 韓信 | male | php0115 | 207 | 21 | 2013-01-15 | 2013-02-20 |
| 8 | 李寧 | male | php0331 | 102 | 24 | 2013-03-31 | 2013-05-05 |
+----+--------+--------+---------+------+------+------------+------------+
從表中選出型別爲桶教授php0115班且爲男性教室屬性相同的教室的信息:
mysql> select gender, c_name from teacher_class where c_name='php0115' and gender='male' limit 1;
+--------+---------+
| gender | c_name |
+--------+---------+
| male | php0115 |
+--------+---------+
mysql> select t_name, gender, c_name from teacher_class where (gender, c_name) = (select gender, c_name from teacher_claame='php0115' and gender='male' limit 1);
+--------+--------+---------+
| t_name | gender | c_name |
+--------+--------+---------+
| 韓信 | male | php0115 |
| 李白 | male | php0115 |
| 韓信 | male | php0115 |
+--------+--------+---------+
3 rows in set (0.00 sec)
注意:處理行子查詢的時候只能處理一行數據。表子查詢
mysql> select t_name, c_name, days from teacher_class where c_name = 'php0115';
+--------+---------+------+
| t_name | c_name | days |
+--------+---------+------+
| 韓信 | php0115 | 21 |
| 李白 | php0115 | 20 |
| 韓非 | php0115 | 15 |
| 韓信 | php0115 | 21 |
+--------+---------+------+
返回的表。mysql> select * from (select t_name, c_name, days from teacher_class where c_name = 'php0115') as temp where t_name like '李%';
+--------+---------+------+
| t_name | c_name | days |
+--------+---------+------+
| 李白 | php0115 | 20 |
+--------+---------+------+
1 row in set (0.00 sec)
注意:外層查詢的時候使用的是內層查詢的表的別名,查詢的列名也是由內層查詢的列名指定的!mysql> select * from (select t_name as tn, c_name as cn, days as dd from teacher_class where c_name = 'php0115') as temp where tn l
ike '李%';
+------+---------+------+
| tn | cn | dd |
+------+---------+------+
| 李白 | php0115 | 20 |
+------+---------+------+
1 row in set (0.00 sec)
exists查詢
mysql> select * from auin_1;
+-----+------+------+
| id | name | sex |
+-----+------+------+
| 1 | ning | boy |
| 5 | Lin | girl |
| 10 | ning | boy |
| 11 | ning | boy |
| 15 | ning | boy |
| 100 | ning | boy |
| 101 | ning | boy |
| 102 | hong | girl |
+-----+------+------+
8 rows in set (0.00 sec)
mysql> select * from teacher_class where exists (select id from auin_1 where teacher_class.id = auin_1.id);
+----+--------+--------+---------+------+------+------------+------------+
| id | t_name | gender | c_name | room | days | begin_date | end_date |
+----+--------+--------+---------+------+------+------------+------------+
| 1 | 韓信 | male | php0115 | 207 | 21 | 2013-01-15 | 2013-02-20 |
| 5 | 李白 | male | php0228 | 204 | 21 | 2013-03-31 | 2013-04-29 |
+----+--------+--------+---------+------+------+------------+------------+
mysql> select * from teacher_class where id in (select id from auin_1);
+----+--------+--------+---------+------+------+------------+------------+
| id | t_name | gender | c_name | room | days | begin_date | end_date |
+----+--------+--------+---------+------+------+------------+------------+
| 1 | 韓信 | male | php0115 | 207 | 21 | 2013-01-15 | 2013-02-20 |
| 5 | 李白 | male | php0228 | 204 | 21 | 2013-03-31 | 2013-04-29 |
+----+--------+--------+---------+------+------+------------+------------+
2 rows in set (0.00 sec)
效率高,但是浪費空間,因爲需要額外的空間保存臨時檢索出來的信息。
join連接查詢
創建表one和two:
mysql> drop table if exists one;
Query OK, 0 rows affected, 1 warning (0.00 sec)
mysql> create table one (
-> one_id int,
-> one_data char(1),
-> public_field int
-> );
Query OK, 0 rows affected (0.06 sec)
mysql> insert into one values
-> (1, 'a', 10),
-> (2, 'b', 20),
-> (3, 'c', 30);
Query OK, 3 rows affected (0.02 sec)
Records: 3 Duplicates: 0 Warnings: 0
mysql> drop table if exists two;
Query OK, 0 rows affected, 1 warning (0.00 sec)
mysql> create table two (
-> two_id int,
-> two_data char(1) not null default 't',
-> public_field int
-> );
Query OK, 0 rows affected (0.05 sec)
mysql> insert into two values
-> (2, 'B', 20),
-> (3, 'C', 30),
-> (4, 'D', 40);
Query OK, 3 rows affected (0.03 sec)
Records: 3 Duplicates: 0 Warnings: 0
mysql> select * from one;
+--------+----------+--------------+
| one_id | one_data | public_field |
+--------+----------+--------------+
| 1 | a | 10 |
| 2 | b | 20 |
| 3 | c | 30 |
+--------+----------+--------------+
3 rows in set (0.00 sec)
mysql> select * from two;
+--------+----------+--------------+
| two_id | two_data | public_field |
+--------+----------+--------------+
| 2 | B | 20 |
| 3 | C | 30 |
| 4 | D | 40 |
+--------+----------+--------------+
3 rows in set (0.00 sec)
內連接:
mysql> select one.one_id, two.two_id, one.one_data, two.two_data from one inner join two on one.one_id = two.two_id;
+--------+--------+----------+----------+
| one_id | two_id | one_data | two_data |
+--------+--------+----------+----------+
| 2 | 2 | b | B |
| 3 | 3 | c | C |
+--------+--------+----------+----------+
2 rows in set (0.00 sec)
所謂內連接就是數據內部的連接,要求連接的多個數據必須存在才能夠進行連接,在上述代碼中我們顯示的用了表明+列名的方式來區分各個表中的內容,當然了,如果兩個表中的列名稱本來就不相同,那就不用區分了。mysql> select one_id, two_id, one_data, two_data from one inner join two on one_id = two_id;
+--------+--------+----------+----------+
| one_id | two_id | one_data | two_data |
+--------+--------+----------+----------+
| 2 | 2 | b | B |
| 3 | 3 | c | C |
+--------+--------+----------+----------+
mysql> select one_id, two_id, one_data, two_data from one inner join two where one_id = two_id;
+--------+--------+----------+----------+
| one_id | two_id | one_data | two_data |
+--------+--------+----------+----------+
| 2 | 2 | b | B |
| 3 | 3 | c | C |
+--------+--------+----------+----------+
2 rows in set (0.00 sec)
第三種表示方法是用using表示方法,使用這種條件限制方法比較有約束力,兩個表的列名必須相同:
mysql> select one_id, two_id, one_data, two_data, one.public_field, two.public_field from one inner join two using(public_field);
+--------+--------+----------+----------+--------------+--------------+
| one_id | two_id | one_data | two_data | public_field | public_field |
+--------+--------+----------+----------+--------------+--------------+
| 2 | 2 | b | B | 20 | 20 |
| 3 | 3 | c | C | 30 | 30 |
+--------+--------+----------+----------+--------------+--------------+
2 rows in set (0.00 sec)
當兩個表中都有pulic_field列名且數值相同的時候才能夠連接成功!mysql> select one_id, two_id, one_data, two_data, one.public_field, two.public_field from one inner join two using(public_field) where one_id >2;
+--------+--------+----------+----------+--------------+--------------+
| one_id | two_id | one_data | two_data | public_field | public_field |
+--------+--------+----------+----------+--------------+--------------+
| 3 | 3 | c | C | 30 | 30 |
+--------+--------+----------+----------+--------------+--------------+
1 row in set (0.00 sec)
內連接的處理
共存在 M X N個連接,這種連接,就稱之爲,交叉連接,或者笛卡爾積。
mysql> select one_id, two_id, one_data, two_data, one.public_field, two.public_field from one inner join two;
+--------+--------+----------+----------+--------------+--------------+
| one_id | two_id | one_data | two_data | public_field | public_field |
+--------+--------+----------+----------+--------------+--------------+
| 1 | 2 | a | B | 10 | 20 |
| 2 | 2 | b | B | 20 | 20 |
| 3 | 2 | c | B | 30 | 20 |
| 1 | 3 | a | C | 10 | 30 |
| 2 | 3 | b | C | 20 | 30 |
| 3 | 3 | c | C | 30 | 30 |
| 1 | 4 | a | D | 10 | 40 |
| 2 | 4 | b | D | 20 | 40 |
| 3 | 4 | c | D | 30 | 40 |
+--------+--------+----------+----------+--------------+--------------+
9 rows in set (0.00 sec)
其實交叉連接(笛卡爾積)有專屬的名字:cross join,在沒有條件過濾的情況下代替inner join。簡而言之,沒有條件的inner join就是cross join
select one_id, two_id, one_data, two_data, one.public_field, two.public_field from one, two;
直接用逗號分開。mysql> select one_id, two_id, one_data, two_data, one.public_field, two.public_field from one join two using(public_field)
-> ;
+--------+--------+----------+----------+--------------+--------------+
| one_id | two_id | one_data | two_data | public_field | public_field |
+--------+--------+----------+----------+--------------+--------------+
| 2 | 2 | b | B | 20 | 20 |
| 3 | 3 | c | C | 30 | 30 |
+--------+--------+----------+----------+--------------+--------------+
2 rows in set (0.00 sec)
注意:
- inner是字段的連接,而union是行的連接。
- 無論是連接條件還是連接查詢多段列表,都沒有必要一定要寫表明.字段的語法,是否寫取決於是否發生衝突,如果不發生衝突的話則沒有必要寫,但是寫上更好,保證代碼的可讀性。
- 表應該別名,保證簡介和清晰。
外連接:
mysql> select one_id, two_id, one_data, two_data, one.public_field, two.public_field from one left join two on one_id = two_id;
+--------+--------+----------+----------+--------------+--------------+
| one_id | two_id | one_data | two_data | public_field | public_field |
+--------+--------+----------+----------+--------------+--------------+
| 1 | NULL | a | NULL | 10 | NULL |
| 2 | 2 | b | B | 20 | 20 |
| 3 | 3 | c | C | 30 | 30 |
+--------+--------+----------+----------+--------------+--------------+
3 rows in set (0.00 sec)
mysql> select one_id, two_id, one_data, two_data, one.public_field, two.public_field from one right join two on one_id = two_id;
+--------+--------+----------+----------+--------------+--------------+
| one_id | two_id | one_data | two_data | public_field | public_field |
+--------+--------+----------+----------+--------------+--------------+
| 2 | 2 | b | B | 20 | 20 |
| 3 | 3 | c | C | 30 | 30 |
| NULL | 4 | NULL | D | NULL | 40 |
+--------+--------+----------+----------+--------------+--------------+
3 rows in set (0.00 sec)
上述代碼表明右表的數據內容始終會出現,而如果左表中沒有相對應的值,則會以NULL的形式存在,也就是說,行數始終等於右邊表的行數。全外連接
mysql> (select one_id, two_id, one_data, two_data, one.public_field, two.public_field from one left join two on one_id = two_id)
-> union
-> (select one_id, two_id, one_data, two_data, one.public_field, two.public_field from one right join two on one_id = two_id);
+--------+--------+----------+----------+--------------+--------------+
| one_id | two_id | one_data | two_data | public_field | public_field |
+--------+--------+----------+----------+--------------+--------------+
| 1 | NULL | a | NULL | 10 | NULL |
| 2 | 2 | b | B | 20 | 20 |
| 3 | 3 | c | C | 30 | 30 |
| NULL | 4 | NULL | D | NULL | 40 |
+--------+--------+----------+----------+--------------+--------------+
4 rows in set (0.00 sec)
mysql> select one_id, two_id, one_data, two_data, one.public_field, two.public_field from one right join two;
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the rig
ht syntax to use near '' at line 1
會去掉結果中的重複字段,並放在列前。相當於左連接,但是會去重!將連接字段放在最前邊。
mysql> select * from one inner join two using (public_field);
+--------------+--------+----------+--------+----------+
| public_field | one_id | one_data | two_id | two_data |
+--------------+--------+----------+--------+----------+
| 20 | 2 | b | 2 | B |
| 30 | 3 | c | 3 | C |
+--------------+--------+----------+--------+----------+
2 rows in set (0.00 sec)
mysql> select * from one left join two using (public_field);
+--------------+--------+----------+--------+----------+
| public_field | one_id | one_data | two_id | two_data |
+--------------+--------+----------+--------+----------+
| 10 | 1 | a | NULL | NULL |
| 20 | 2 | b | 2 | B |
| 30 | 3 | c | 3 | C |
+--------------+--------+----------+--------+----------+
3 rows in set (0.00 sec)
自然連接
自然連接分成 內外之分:
內:natural join,相當於帶using條件的inner join
外:左外,右外。
Natural left join
Natural right join
mysql> select * from one natural join two;
+--------------+--------+----------+--------+----------+
| public_field | one_id | one_data | two_id | two_data |
+--------------+--------+----------+--------+----------+
| 20 | 2 | b | 2 | B |
| 30 | 3 | c | 3 | C |
+--------------+--------+----------+--------+----------+
2 rows in set (0.00 sec)
自然左內連接,相當於帶using條件的左連接:
mysql> select * from one natural left join two;
+--------------+--------+----------+--------+----------+
| public_field | one_id | one_data | two_id | two_data |
+--------------+--------+----------+--------+----------+
| 10 | 1 | a | NULL | NULL |
| 20 | 2 | b | 2 | B |
| 30 | 3 | c | 3 | C |
+--------------+--------+----------+--------+----------+
3 rows in set (0.00 sec)
習題一:
mysql> drop table if exists my_dept;
Query OK, 0 rows affected, 1 warning (0.00 sec)
mysql> create table my_dept(
-> id int primary key auto_increment,
-> dept_name varchar(20),
-> parent_id int
-> )character set utf8;
Query OK, 0 rows affected (0.09 sec)
mysql> insert into my_dept values
-> (null, '行政部', 0),
-> (null, '教學部', 0),
-> (null, 'php', 2),
-> (null, 'java', 2),
-> (null, '.net', 2),
-> (null, '平面', 2),
-> (null, '諮詢', 1),
-> (null, '財務', 1);
Query OK, 8 rows affected (0.02 sec)
Records: 8 Duplicates: 0 Warnings: 0
mysql> select * from my_dept;
+----+-----------+-----------+
| id | dept_name | parent_id |
+----+-----------+-----------+
| 1 | 行政部 | 0 |
| 2 | 教學部 | 0 |
| 3 | php | 2 |
| 4 | java | 2 |
| 5 | .net | 2 |
| 6 | 平面 | 2 |
| 7 | 諮詢 | 1 |
| 8 | 財務 | 1 |
+----+-----------+-----------+
8 rows in set (0.02 sec)
mysql> select * from my_dept where parent_id = 0;
+----+-----------+-----------+
| id | dept_name | parent_id |
+----+-----------+-----------+
| 1 | 行政部 | 0 |
| 2 | 教學部 | 0 |
+----+-----------+-----------+
2 rows in set (0.00 sec)
mysql> select * from my_dept where parent_id in (select id from my_dept where dept_name = '教學部');
+----+-----------+-----------+
| id | dept_name | parent_id |
+----+-----------+-----------+
| 3 | php | 2 |
| 4 | java | 2 |
| 5 | .net | 2 |
| 6 | 平面 | 2 |
+----+-----------+-----------+
4 rows in set (0.01 sec)
連接方法:
mysql> select * from my_dept as c inner join my_dept as p on c.parent_id = p.id where p.dept_name = '教學部';
+----+-----------+-----------+----+-----------+-----------+
| id | dept_name | parent_id | id | dept_name | parent_id |
+----+-----------+-----------+----+-----------+-----------+
| 3 | php | 2 | 2 | 教學部 | 0 |
| 4 | java | 2 | 2 | 教學部 | 0 |
| 5 | .net | 2 | 2 | 教學部 | 0 |
| 6 | 平面 | 2 | 2 | 教學部 | 0 |
+----+-----------+-----------+----+-----------+-----------+
4 rows in set (0.00 sec)
習題二:
Select h.class_name, g.class_name, m.match_time, m.match_result
From `match` as m left join class as h on m.host_id =h.id left join class as g on
m.guest_id=g.id where m.match_time between '2013-04-01' and '2013-04-30';