測試環境為 CentOS 7 x86_64 虛擬機.
多個資料表單有相對應的欄位時,我們可以透過 JOIN 來同時查詢多個資料表單的資料.
[root@localhost ~]# mysql -u root -p Enter password: Welcome to the MariaDB monitor. Commands end with ; or \g. Your MariaDB connection id is 25 Server version: 5.5.60-MariaDB MariaDB Server Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. MariaDB [(none)]> CREATE DATABASE testdb; Query OK, 1 row affected (0.00 sec) MariaDB [(none)]> USE testdb; Database changed
下面範例有兩個 Table.
- project (存放專案名稱與相對應人員名單)
project 這個資料表主要儲存專案的相關資料.MariaDB [testdb]> CREATE TABLE project (K1 int(11) NOT NULL auto_increment , name varchar(199) NOT NULL , member varchar(199) NOT NULL, PRIMARY KEY (K1)); Query OK, 0 rows affected (0.02 sec) MariaDB [testdb]> DESCRIBE project; +--------+--------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +--------+--------------+------+-----+---------+----------------+ | K1 | int(11) | NO | PRI | NULL | auto_increment | | name | varchar(199) | NO | | NULL | | | member | varchar(199) | NO | | NULL | | +--------+--------------+------+-----+---------+----------------+ 3 rows in set (0.02 sec)
在 project 資料表建立專案與個別成員資料資料.
MariaDB [testdb]> INSERT INTO project (name , member) VALUES('A','Ben') , ('A','Jason') , ('A','Thomas') , ('B','Jack') , ('B','Andy') , ('B','Chuck') , ('C','Jack') , ('C','Jason') , ('C','Chuck'); Query OK, 9 rows affected (0.003 sec) Records: 9 Duplicates: 0 Warnings: 0 MariaDB [testdb]> SELECT * FROM project; +----+------+--------+ | K1 | name | member | +----+------+--------+ | 1 | A | Ben | | 2 | A | Jason | | 3 | A | Thomas | | 4 | B | Jack | | 5 | B | Andy | | 6 | B | Chuck | | 7 | C | Jack | | 8 | C | Jason | | 9 | C | Chuck | +----+------+--------+ 9 rows in set (0.00 sec)
- staff (存放員工姓名與部門)
staff 這個資料表主要儲存員工的相關資料.MariaDB [testdb]> CREATE TABLE staff (K1 int(11) NOT NULL auto_increment , name varchar(199) NOT NULL , dept varchar(199) NOT NULL, PRIMARY KEY (K1)); Query OK, 0 rows affected (0.02 sec) MariaDB [testdb]> DESCRIBE staff; +-------+--------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +-------+--------------+------+-----+---------+----------------+ | K1 | int(11) | NO | PRI | NULL | auto_increment | | name | varchar(199) | NO | | NULL | | | dept | varchar(199) | NO | | NULL | | +-------+--------------+------+-----+---------+----------------+ 3 rows in set (0.00 sec)
並在 staff Table 建立了員工 Ben , Jason , Thomas , Jack , Andy , Chuck 與其相對應的部門資料.
MariaDB [testdb]> INSERT INTO staff (name , dept) VALUES('Ben','HR') , ('Jason','HW') , ('Thomas','Test') , ('Jack','PM') , ('Andy','Test') , ('Chuck','SW'); Query OK, 6 rows affected (0.002 sec) Records: 6 Duplicates: 0 Warnings: 0 MariaDB [testdb]> SELECT * FROM staff; +----+--------+------+ | K1 | name | dept | +----+--------+------+ | 1 | Ben | HR | | 2 | Jason | HW | | 3 | Thomas | Test | | 4 | Jack | PM | | 5 | Andy | Test | | 6 | Chuck | SW | +----+--------+------+ 6 rows in set (0.01 sec)
JOIN
在 project 資料表中有 member 姓名,在 staff 也有員工姓名,兩者的資料表皆有相對應的資料時就可以透過 Join 的方式直接把資料 SELECT 出來.Join 有下面幾種方式.
- WHERE A=B
利用 WHERE A=B 的指定方式查詢獲得 專案 A 與其成員和單位.SELECT project.name , project.member , staff.dept FROM project , staff WHERE project.member=staff.name AND project.name='A';
MariaDB [testdb]> SELECT project.name , project.member , staff.dept FROM project , staff WHERE project.member=staff.name AND project.name='A'; +------+--------+------+ | name | member | dept | +------+--------+------+ | A | Ben | HR | | A | Jason | HW | | A | Thomas | Test | +------+--------+------+ 3 rows in set (0.00 sec)
因為有多個表格,欄位指定會變很長,通常會使用表格別名來為個別資料表命名, project 別名為 p , staff 別名為 s , 使用 p 與 s 就可以直接代表 project 與 staff 資料表.
SELECT p.name , p.member , s.dept FROM project p, staff s WHERE p.member=s.name AND p.name='A';
MariaDB [testdb]> SELECT p.name , p.member , s.dept FROM project p, staff s WHERE p.member=s.name AND p.name='A'; +------+--------+------+ | name | member | dept | +------+--------+------+ | A | Ben | HR | | A | Jason | HW | | A | Thomas | Test | +------+--------+------+ 3 rows in set (0.00 sec)
- CROSS JOIN
就字面上的字義,把所有相對應資料全部交叉顯示,如下把 Project A 的資料全部對交叉顯示.SELECT project.name , project.member , staff.dept FROM project CROSS JOIN staff WHERE project.name='A';
執行結果.
MariaDB [testdb]> SELECT project.name , project.member , staff.dept -> FROM project -> CROSS JOIN staff -> WHERE project.name='A'; +------+--------+------+ | name | member | dept | +------+--------+------+ | A | Ben | HR | | A | Ben | HW | | A | Ben | Test | | A | Ben | PM | | A | Ben | Test | | A | Ben | SW | | A | Jason | HR | | A | Jason | HW | | A | Jason | Test | | A | Jason | PM | | A | Jason | Test | | A | Jason | SW | | A | Thomas | HR | | A | Thomas | HW | | A | Thomas | Test | | A | Thomas | PM | | A | Thomas | Test | | A | Thomas | SW | +------+--------+------+ 18 rows in set (0.000 sec)
- INNER JOIN
利用 Inner Join 的指定方式查詢獲得 專案 A 與其成員和單位.SELECT project.name , project.member , staff.dept FROM project INNER JOIN staff ON project.member = staff.name WHERE project.name='A';
MariaDB [testdb]> SELECT project.name , project.member , staff.dept FROM project INNER JOIN staff ON project.member = staff.name WHERE project.name='A'; +------+--------+------+ | name | member | dept | +------+--------+------+ | A | Ben | HR | | A | Jason | HW | | A | Thomas | Test | +------+--------+------+ 3 rows in set (0.01 sec)
因為有多個表格,欄位指定會變很長,通常會使用表格別名來為個別資料表命名, project 別名為 p , staff 別名為 s , 使用 p 與 s 就可以直接代表 project 與 staff 資料表.
SELECT p.name , p.member , s.dept FROM project p INNER JOIN staff s ON p.member = s.name WHERE p.name='A';
MariaDB [testdb]> SELECT p.name , p.member , s.dept FROM project p INNER JOIN staff s ON p.member = s.name WHERE p.name='A'; +------+--------+------+ | name | member | dept | +------+--------+------+ | A | Ben | HR | | A | Jason | HW | | A | Thomas | Test | +------+--------+------+ 3 rows in set (0.00 sec)
- INNER JOIN USING
前面範例使用 JOIN staff ON 如果後面兩個資料表欄位名稱皆相同時,可以用 JOIN staff USING(欄位名). - LEFT / RIGHT OUTER JOIN
下面透過 GROUP_CONCAT 與 CONCAT 函數(可以把多個欄位文字整合在一起) 把所有的案子,成員與其相對應部門讀取出來.SELECT p.name , GROUP_CONCAT(CONCAT(p.member ,':',s.dept) SEPARATOR ',') AS "Members:Dept." FROM project p INNER JOIN staff s ON p.member = s.name GROUP BY name;
MariaDB [testdb]> SELECT p.name , GROUP_CONCAT(CONCAT(p.member ,':',s.dept) SEPARATOR ',') AS "Members:Dept." FROM project p INNER JOIN staff s ON p.member = s.name GROUP BY name; +------+-----------------------------+ | name | Members:Dept. | +------+-----------------------------+ | A | Jason:HW,Thomas:Test,Ben:HR | | B | Andy:Test,Chuck:SW,Jack:PM | | C | Jack:PM,Jason:HW,Chuck:SW | +------+-----------------------------+ 3 rows in set (0.00 sec)
現在多了一個案子 D ,不過成員還沒決定.
MariaDB [testdb]> INSERT INTO project (name) VALUES('D'); Query OK, 1 row affected, 1 warning (0.00 sec)
並透過剛剛的方式把所有的案子,成員與其相對應部門讀取出來.
SELECT p.name , GROUP_CONCAT(CONCAT(p.member ,':',s.dept) SEPARATOR ',') AS "Members:Dept." FROM project p INNER JOIN staff s ON p.member = s.name GROUP BY name;
MariaDB [testdb]> SELECT p.name , GROUP_CONCAT(CONCAT(p.member ,':',s.dept) SEPARATOR ',') AS "Members:Dept." FROM project p INNER JOIN staff s ON p.member = s.name GROUP BY name; +------+-----------------------------+ | name | Members:Dept. | +------+-----------------------------+ | A | Jason:HW,Thomas:Test,Ben:HR | | B | Andy:Test,Chuck:SW,Jack:PM | | C | Jack:PM,Jason:HW,Chuck:SW | +------+-----------------------------+ 3 rows in set (0.00 sec)
奇怪為什麼案子 D 的資料沒有出現, INNER JOIN 只會把符合 p.member = s.name 的資料顯示出來,案子 D 沒有 member 所以就不顯示,這時候需要改用 OUTER JOIN.
OUTER JOIN 有 LEFT / RIGHT 兩種,這邊範例是以 LEFT (以 project 資料表為主 ) OUTER JOIN ,這時候就可以看到 案子 D 的資料了.
SELECT p.name , GROUP_CONCAT(CONCAT(p.member ,':',s.dept) SEPARATOR ',') AS "Members:Dept." FROM project p LEFT OUTER JOIN staff s ON p.member = s.name GROUP BY name;
MariaDB [testdb]> SELECT p.name , GROUP_CONCAT(CONCAT(p.member ,':',s.dept) SEPARATOR ',') AS "Members:Dept." FROM project p LEFT OUTER JOIN staff s ON p.member = s.name GROUP BY name; +------+-----------------------------+ | name | Members:Dept. | +------+-----------------------------+ | A | Ben:HR,Thomas:Test,Jason:HW | | B | Chuck:SW,Andy:Test,Jack:PM | | C | Jason:HW,Jack:PM,Chuck:SW | | D | NULL | +------+-----------------------------+ 4 rows in set (0.01 sec)
- SELECT INNER JOIN (Right / LEFT OUTER) (SELECT)
JOIN 後面除了接資料表外還可以使用 SELECT 得來的資料.SELECT p.name , p.member , s.dept FROM project p INNER JOIN (SELECT * FROM staff) s ON p.member = s.name WHERE p.name='A';
MariaDB [testdb]> SELECT p.name , p.member , s.dept FROM project p INNER JOIN (SELECT * FROM staff) s ON p.member = s.name WHERE p.name='A'; +------+--------+------+ | name | member | dept | +------+--------+------+ | A | Ben | HR | | A | Jason | HW | | A | Thomas | Test | +------+--------+------+ 3 rows in set (0.00 sec)
- SELECT (SELECT) INNER (Right / LEFT OUTER) JOIN (SELECT)
如果是兩個查詢 (SELECT) 後的資料表 (Table) ,一樣可以使用 JOIN ,把兩個查詢後資料表 (Table) 結合再一起.要來看 A 案子的成員是否與 C 案子有重覆.
SELECT a.member , a.name , b.name FROM (SELECT name , member FROM project WHERE name='A') AS a LEFT OUTER JOIN (SELECT name , member FROM project WHERE name='C') AS b ON a.member = b.member;
MariaDB [testdb]> SELECT name , member FROM project WHERE name='A'; +----+------+--------+ | K1 | name | member | +----+------+--------+ | 1 | A | Ben | | 2 | A | Jason | | 3 | A | Thomas | +----+------+--------+ 3 rows in set (0.002 sec) MariaDB [testdb]> SELECT name , member FROM project WHERE name='C'; +----+------+--------+ | K1 | name | member | +----+------+--------+ | 7 | C | Jack | | 8 | C | Jason | | 9 | C | Chuck | +----+------+--------+ 3 rows in set (0.001 sec) MariaDB [testdb]> SELECT a.member , a.name , b.name FROM (SELECT name , member FROM project WHERE name='A') AS a LEFT OUTER JOIN (SELECT name , member FROM project WHERE name='C') AS b ON a.member = b.member; +--------+------+------+ | member | name | name | +--------+------+------+ | Jason | A | C | | Ben | A | NULL | | Thomas | A | NULL | +--------+------+------+ 3 rows in set (0.001 sec)