MySql基礎入門到進階

1. 基本操作

登錄:

mysql -u root -p

輸入密碼,登陸數據庫

創建數據庫 study

CREATE DATABASE study CHARACTER SET UTF8;

刪除數據庫:

DROP DATABASE 數據庫名;

查看所有的數據庫:

SHOW DATABASES;

使用數據庫 study

USE study;

創建數據表 news

CREATE TABLE news (
	nid INT AUTO_INCREMENT,
	title VARCHAR(30) NOT NULL,
	content VARCHAR(300),
	CONSTRAINT pk_nid PRIMARY KEY(nid)
)ENGINE = INNODB DEFAULT CHARSET=utf8;

插入數據:

INSERT INTO news(title, content) VALUES('mysql study', 'this is test data');
INSERT INTO news(title, content) VALUES('mysql study', 'this is test data');
INSERT INTO news(title, content) VALUES('mysql study', 'this is test data');

主鍵設置了自增,所以插入數據時可以省略此字段

獲得自增後的主鍵:

SELECT LAST_INSERT_ID();

刪除數據:

DELETE FROM news WHERE nid = 2;

修改數據:

UPDATE news SET content='this is update test' WHERE nid=1; 

2. 查詢操作

數據表準備:

--
-- Table structure for table `dept`
--
DROP TABLE IF EXISTS `dept`;
CREATE TABLE `dept` (
  `deptno` INT(2) NOT NULL,
  `dname` VARCHAR(14) DEFAULT NULL,
  `loc` VARCHAR(13) DEFAULT NULL,
  PRIMARY KEY  (`deptno`)
) ENGINE=INNODB DEFAULT CHARSET=utf8;
--
-- Dumping data for table `dept`
--
INSERT INTO `dept` VALUES (10,'ACCOUNTING','NEW YORK'),(20,'RESEARCH','DALLAS'),(30,'SALES','CHICAGO'),(40,'OPERATIONS','BOSTON'),(60,'HR','SY');

--
-- Table structure for table `emp`
--
DROP TABLE IF EXISTS `emp`;
CREATE TABLE `emp` (
  `empno` INT(4) NOT NULL,
  `ename` VARCHAR(20) DEFAULT NULL,
  `job` VARCHAR(9) DEFAULT NULL,
  `mgr` INT(4) DEFAULT NULL,
  `hiredate` DATE DEFAULT NULL,
  `sal` DOUBLE(7,2) DEFAULT NULL,
  `comm` DOUBLE(7,2) DEFAULT NULL,
  `deptno` INT(2) DEFAULT NULL,
  PRIMARY KEY  (`empno`)
) ENGINE=INNODB DEFAULT CHARSET=utf8;
--
-- Dumping data for table `emp`
--
INSERT INTO `emp` VALUES (7369,'SMITH','CLERK',7902,'1980-12-17',800.00,NULL,20),(7499,'ALLEN','SALESMAN',7698,'1981-02-20',1600.00,300.00,30),(7521,'WARD','SALESMAN',7698,'1981-02-22',1250.00,500.00,30),(7566,'JONES','MANAGER',7839,'1981-04-02',2975.00,NULL,20),(7654,'MARTIN','SALESMAN',7698,'1981-09-28',1250.00,1400.00,30),(7698,'BLAKE','MANAGER',7839,'1981-05-01',2850.00,NULL,30),(7782,'CLARK','MANAGER',7839,'1981-06-09',2450.00,NULL,10),(7788,'SCOTT','ANALYST',7566,'1987-04-19',3000.00,NULL,20),(7839,'KING','PRESIDENT',NULL,'1981-11-17',5000.00,NULL,10),(7844,'TURNER','SALESMAN',7698,'1981-09-08',1500.00,0.00,30),(7876,'ADAMS','CLERK',7788,'1987-05-23',1100.00,NULL,20),(7900,'JAMES','CLERK',7698,'1981-12-03',950.00,NULL,30),(7902,'FORD','ANALYST',7566,'1981-12-03',3000.00,NULL,20),(7934,'MILLER','CLERK',7782,'1982-01-23',1300.00,NULL,10);

--
-- Table structure for table `salgrade`
--

DROP TABLE IF EXISTS `salgrade`;
CREATE TABLE `salgrade` (
  `grade` INT(11) DEFAULT NULL,
  `losal` INT(11) DEFAULT NULL,
  `hisal` INT(11) DEFAULT NULL
) ENGINE=INNODB DEFAULT CHARSET=utf8;
--
-- Dumping data for table `salgrade`
--
INSERT INTO `salgrade` VALUES (1,700,1200),(2,1201,1400),(3,1401,2000),(4,2001,3000),(5,3001,9999);

--
-- Table structure for table `bonus`
--
CREATE TABLE `bonus` (
  `ename` VARCHAR(20) DEFAULT NULL,
  `job` VARCHAR(9) DEFAULT NULL,
  `sal` DOUBLE(7,2) DEFAULT NULL,
  `comm` DOUBLE(7,2) DEFAULT NULL
) ENGINE = INNODB default charset utf8;

2.1 簡單查詢

最基本的查詢,語法:

SELECT [DISTINCT] *|列[別名],列[別名],...
FROM 表名稱 [別名];
  • 語句執行順序:1. FROM 2. SELECT;
  • DISTINCT :去掉重複行數據;
  • * :查詢所有列,如果不想查詢所有列,可以寫上具體列名稱;
  • 在拿到一個未知的數據庫是,千萬不要查詢全部,不然...
  • 別名:與列名稱以空格分開,將替代原列名稱顯示在結果的表頭;
  • SELECT 子句中的“列”可以進行數學計算 + - * / %。

例一:

select empno 員工編號, ename 員工姓名, job 崗位, mgr 領導, hiredate 入職日期, sal*12 年薪, comm 獎金, deptno 部門編號 from emp;

練習

要求:查詢所有僱員編號,僱員姓名, 每月總收入,所在部門。

select empno, ename, sal + ifnull(comm,0) from emp;
  • NULL 值和任何數據進行計算,結果都是 NULL
  • IFNULL(expr1,expr2) 如果 expr1 不是 NULLIFNULL() 返回 expr1,否則它返回 expr2

2.2 分頁查詢

數據庫級別的分頁查詢,語法:

查詢語句 LIMIT 開始行,長度;

 

  • 開始行索引從 0 開始。
  • LIMIT 子句是整個查詢的最後一句.

2.3 限定查詢

針對查詢結果進行條件過濾,語法:

SELECT [DISTINCT] *|列[別名],列[別名],...
FROM 表名稱 [別名]
[WHERE 條件];
  • 語句執行順序:1. FROM 2. WHERE 3. SELECT
    WHERE子句中的條件可以是多條,該子句可以以下操作符:
    • 關係運算符:> >= < <= <> !=
    • 範圍運算符:BETWEEN ... AND ...
      • 字段 BETWEEN 最小值 AND 最大值
      • 注意:範圍中包含最大值和最小值;
    • 邏輯運算符:AND(與)、 OR(或)、 NOT(非);
    • 空判斷運算符:IS NULLIS NOT NULL
      • 不能用邏輯運算符來進行空判斷,比如“comm != null”,正確的是 “comm IS NOT NULL”;
      • 注意,對數據庫來說,0 和 null 是不一樣的概念;
    • 基數範圍:INNOT IN
      • 表示在或者不在某幾個可選數值範圍之中;
      • 字段 IN/NOT IN (數值, 數值,...)
      • 注意:在使用 NOT IN 時,如果基數中包含了 NULL ,則無論有沒有滿足要求的數據,都不會被顯示,這是一種保護機制;
    • 模糊查詢:LIKE
      • 字段 LIKE '匹配的關鍵字'
      • _:表示匹配任意 一個 字符
      • %:表示匹配任意 0個,1個,或多個關鍵字;
      • 如果不使用任何通配符,則表示精確匹配。

相關練習

  1. 要求:查詢出所有銷售人員(SALESMAN)中工資高於 1200 的僱員信息。
SELECT * FROM emp WHERE job = 'salesman' AND sal > 1200;
  1. 要求:查詢出工資在 1200 ~ 3000 之間的僱員信息。
SELECT * FROM emp WHERE sal BETWEEN 1200 AND 3000;
  1. 要求:查詢出所有在 1981 年僱傭的僱員信息。
SELECT * FROM emp WHERE hiredate BETWEEN '1981-01-01' AND '1981-12-31';
  1. 要求:查詢所有領取佣金的僱員,即 comm 不爲 null。
SELECT * FROM emp WHERE comm IS NOT NULL;
  1. 要求:查詢出僱員編號爲 7369,7566,7839,8899 的僱員。
SELECT * FROM emp WHERE empno IN (7369,7566,7839,8899);
  1. 要求:查詢出姓名中第二個字母是'A'的僱員。
SELECT * FROM emp WHERE ename LIKE '_A%';

2.4 查詢排序

對查詢的結果進行排序,語法:

SELECT [DISTINCT] *|列[別名],列[別名],...
FROM 表名稱 [別名]
[WHERE 條件]
[ORDER BY 字段[ASC|DESC],字段[ASC|DESC],...];
  • 語句執行順序:1. FROM 2. WHERE 3. SELECT 4. ORDER BY
  • 因爲ORDER BY子句是整個查詢的倒數第二句,所以可以使用在 SELECT 子句中定義的別名;
  • ASC 表示升序,是默認方式
  • DESC 表示降序。

相關練習

  1. 要求:查詢出所有僱員的信息,結果按照工資由高到低排序,如果工資相同,則按照入職日期從早到晚排序。
SELECT * FROM emp ORDER BY sal DESC, hiredate;
  1. 要求:查詢出所有僱員的信息,按照年薪排序。
SELECT * FROM emp ORDER BY sal*12 ;

2.5 思考題

  1. 要求:查詢部門 30 中的所有員工。
select * from emp where deptno = 30;
  1. 要求:查詢所有辦事員(CLERK)的姓名,編號,部門編號。
select ename, empno,job, deptno from emp where job = 'CLERK';
  1. 要求:查詢出佣金高於工資 60 % 的僱員。
select * from emp where comm > sal*0.6
  1. 要求:查詢出部門 10 中所有的經理 和 部門 20 中所有的辦事員。
select * from emp where (deptno = 10 and job = 'manager') or (deptno = 20 and job = 'CLERK');
  1. 要求:查詢出部門 10 中所有的經理 、 部門 20 中所有的辦事員 、 既不是經理又不是辦事員,但其工資大於等於 2000 的僱員信息。
select * from emp where (deptno = 10 and job = 'manager') or (deptno = 20 and job = 'CLERK') or (job != 'manager' and job != 'clerk' and sal > 2000);
  1. 要求:查詢出收入組成中有佣金的員工的不同工作。
select distinct job from emp where comm is not null;
  1. 要求:查詢出收入組成中無佣金 或者佣金收入低於 100 的僱員信息。
select * from emp where comm is null or comm < 100;
  1. 要求:查詢姓名中沒有 “R” 的員工姓名。
select ename from emp where ename not like '%R%';
  1. 要求:查詢姓名中有 “A” 的僱員信息,結果按照工資由高到低排序,如果工資相同,則按照入職早晚排序,如果入職日期相同,則按照崗位排序。
select * from emp where ename like '%A%' order by sal desc,hiredate,job;

2.6 多表查詢

具有關聯字段的表,以關聯字段關係判斷進行的查詢,其中內連接查詢語法:

SELECT [DISTINCT] *|列[別名],列[別名],...
FROM 數據表1 [別名], 數據表2 [別名],...
WHERE 數據表1.關聯字段 = 數據表2.關聯字段...
[ORDER BY 字段[ASC|DESC],字段[ASC|DESC],...];
或者
SELECT [DISTINCT] *|列[別名],列[別名],...
FROM 數據表1 [別名] [INNER] JOIN 數據表2 [別名] ON 關聯條件
[ORDER BY 字段[ASC|DESC],字段[ASC|DESC],...];
  • 如果指定關聯表,但是並不在 WHERE 子句中指定關聯字段,則查詢的結果將會是兩個數據表的"笛卡兒積",其實指定了關聯字段,這個"笛卡兒積"依然存在,只是被過濾掉了。所以,在數據量比較大的情況下,多表關聯查詢的效率是比較差的。

相關練習

  1. 要求:查詢每個僱員的編號,姓名,職位,工資,部門名稱,部門位置。
SELECT empno, ename, job, sal, dname, loc FROM emp, dept WHERE emp.deptno = dept.deptno; 

-- 或者 

SELECT empno, ename, job, sal, dname, loc FROM emp INNER JOIN dept ON dept.deptno=emp.deptno;
  1. 要求:查詢每個僱員的編號,姓名,職位,工資,入職日期,工資等級。
SELECT empno, ename, job, sal, hiredate, grade FROM emp, salgrade WHERE emp.sal BETWEEN salgrade.losal AND salgrade.hisal; 

-- 或者

 SELECT empno, ename, job, sal, hiredate, grade FROM emp INNER JOIN salgrade ON emp.sal BETWEEN salgrade.losal AND salgrade.hisal;

多表查詢的連接方式

多表查詢的連接方式有兩種:

  • 內連接:默認爲等值連接、上面的案例就是內連接;

在使用內連接進行多表查詢的時候,如果其中一條數據,在關聯表中沒有符合條件的對應值,這時本條數據就不會被顯示。

案例:查詢每個僱員的編號,姓名,職位,領導姓名.
使用內連接:

SELECT e.empno, e.ename, e.job, m.ename FROM emp e, emp m WHERE e.mgr = m.empno; 

-- 或者

SELECT e.empno, e.ename, e.job, m.ename FROM emp e inner join emp m on e.mgr = m.empno;

可以看到,編號 7839 的僱員信息沒有出現在結果中,因爲他沒有領導(老大).

  • 外連接:分爲 左外連接、右外連接、全連接。
    外連接語法:
SELECT [DISTINCT] *|列[別名],列[別名],...
FROM 數據表1 [別名] LEFT|RIGHT|FULL [OUTER] JOIN 數據表2 [別名] ON 關聯條件
[ORDER BY 字段[ASC|DESC],字段[ASC|DESC],...];

注意:全外連接的 FULL,MySQL 暫不支持,需要使用 查詢結果連接符 UNIONUNION 操作會將兩個 SELECT 語句的查詢結果連接起來,並且會去掉重複數據。

用外連接改寫上面的案例:

SELECT e.empno, e.ename, e.job, m.ename FROM emp e left outer join emp m on e.mgr = m.empno;

爲了更清楚的說明問題,新建一張 myemp 的表,減少 emp 表中的字段:

CREATE TABLE myemp
( `empno` INT(4) NOT NULL AUTO_INCREMENT, 
`ename` VARCHAR(20) DEFAULT NULL, 
`deptno` INT(2) DEFAULT NULL,
 CONSTRAINT pk_empno PRIMARY KEY (`empno`) 
)ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

插入測試數據:

INSERT INTO myemp(ename, deptno) VALUES('SMITH', 10); 
INSERT INTO myemp(ename, deptno) VALUES('ALLEN', 10); 
INSERT INTO myemp(ename, deptno) VALUES('WARD', 10); 
INSERT INTO myemp(ename, deptno) VALUES('JONES', 20); 
INSERT INTO myemp(ename, deptno) VALUES('MARTIN', 20); 
INTO myemp(ename, deptno) VALUES('BLAKE', 30); 
INSERT INTO myemp(ename, deptno) VALUES('CLARK', 40); 
INSERT INTO myemp(ename, deptno) VALUES('SCOTT', 50);

先觀察內連接(等值連接):

SELECT * FROM myemp m INNER JOIN dept d ON m.`deptno`=d.`deptno`;

查詢結果:

mysql> SELECT * FROM myemp e INNER JOIN dept d ON e.`deptno`=d.`deptno`;
+-------+--------+--------+--------+------------+----------+
| empno | ename  | deptno | deptno | dname      | loc      |
+-------+--------+--------+--------+------------+----------+
|     1 | SMITH  |     10 |     10 | ACCOUNTING | NEW YORK |
|     2 | ALLEN  |     10 |     10 | ACCOUNTING | NEW YORK |
|     3 | WARD   |     10 |     10 | ACCOUNTING | NEW YORK |
|     4 | JONES  |     20 |     20 | RESEARCH   | DALLAS   |
|     5 | MARTIN |     20 |     20 | RESEARCH   | DALLAS   |
|     6 | BLAKE  |     30 |     30 | SALES      | CHICAGO  |
|     7 | CLARK  |     40 |     40 | OPERATIONS | BOSTON   |
+-------+--------+--------+--------+------------+----------+
7 rows in set (0.00 sec)

可以發現,結果是兩個表關聯字段的交集:

左外連接:

SELECT * FROM myemp m LEFT OUTER JOIN dept d ON m.`deptno`=d.`deptno`;

查詢結果:

mysql> SELECT * FROM myemp m LEFT OUTER JOIN dept d ON m.`deptno`=d.`deptno`;
+-------+--------+--------+--------+------------+----------+
| empno | ename  | deptno | deptno | dname      | loc      |
+-------+--------+--------+--------+------------+----------+
|     1 | SMITH  |     10 |     10 | ACCOUNTING | NEW YORK |
|     2 | ALLEN  |     10 |     10 | ACCOUNTING | NEW YORK |
|     3 | WARD   |     10 |     10 | ACCOUNTING | NEW YORK |
|     4 | JONES  |     20 |     20 | RESEARCH   | DALLAS   |
|     5 | MARTIN |     20 |     20 | RESEARCH   | DALLAS   |
|     6 | BLAKE  |     30 |     30 | SALES      | CHICAGO  |
|     7 | CLARK  |     40 |     40 | OPERATIONS | BOSTON   |
|     8 | SCOTT  |     50 |   NULL | NULL       | NULL     |
+-------+--------+--------+--------+------------+----------+
8 rows in set (0.00 sec)

可以發現,結果是左邊的表是完整的,右邊的表只保留交集部分:


右外連接:

SELECT * FROM myemp m RIGHT OUTER JOIN dept d ON m.`deptno`=d.`deptno`;

查詢結果:

mysql> SELECT * FROM myemp m RIGHT OUTER JOIN dept d ON m.`deptno`=d.`deptno`;
+-------+--------+--------+--------+------------+----------+
| empno | ename  | deptno | deptno | dname      | loc      |
+-------+--------+--------+--------+------------+----------+
|     1 | SMITH  |     10 |     10 | ACCOUNTING | NEW YORK |
|     2 | ALLEN  |     10 |     10 | ACCOUNTING | NEW YORK |
|     3 | WARD   |     10 |     10 | ACCOUNTING | NEW YORK |
|     4 | JONES  |     20 |     20 | RESEARCH   | DALLAS   |
|     5 | MARTIN |     20 |     20 | RESEARCH   | DALLAS   |
|     6 | BLAKE  |     30 |     30 | SALES      | CHICAGO  |
|     7 | CLARK  |     40 |     40 | OPERATIONS | BOSTON   |
|  NULL | NULL   |   NULL |     60 | HR         | SY       |
+-------+--------+--------+--------+------------+----------+
8 rows in set (0.00 sec)

可以發現,結果是右邊的表是完整的,左邊的表只保留交集部分:

全外連接:

SELECT * FROM myemp m LEFT OUTER JOIN dept d ON m.`deptno`=d.`deptno` 
UNION 
SELECT * FROM myemp m RIGHT OUTER JOIN dept d ON m.`deptno`=d.`deptno`;

查詢結果:

mysql> SELECT * FROM myemp m LEFT OUTER JOIN dept d ON m.`deptno`=d.`deptno`
    -> UNION
    -> SELECT * FROM myemp m RIGHT OUTER JOIN dept d ON m.`deptno`=d.`deptno`;
+-------+--------+--------+--------+------------+----------+
| empno | ename  | deptno | deptno | dname      | loc      |
+-------+--------+--------+--------+------------+----------+
|     1 | SMITH  |     10 |     10 | ACCOUNTING | NEW YORK |
|     2 | ALLEN  |     10 |     10 | ACCOUNTING | NEW YORK |
|     3 | WARD   |     10 |     10 | ACCOUNTING | NEW YORK |
|     4 | JONES  |     20 |     20 | RESEARCH   | DALLAS   |
|     5 | MARTIN |     20 |     20 | RESEARCH   | DALLAS   |
|     6 | BLAKE  |     30 |     30 | SALES      | CHICAGO  |
|     7 | CLARK  |     40 |     40 | OPERATIONS | BOSTON   |
|     8 | SCOTT  |     50 |   NULL | NULL       | NULL     |
|  NULL | NULL   |   NULL |     60 | HR         | SY       |
+-------+--------+--------+--------+------------+----------+
9 rows in set (0.00 sec)

可以發現,全外連接中,兩個表都保證了完整性:

總結:
如果想要保證 JOIN 左邊的表的完整性,使用 LEFT OUTER JOIN 連接;
如果想要保證 JOIN 右邊的表的完整性,使用 RIGHT OUTER JOIN 連接;
如果想要保證 JOIN 兩邊的表的完整性,使用 UNION 連接左外連接查詢和右外連接查詢;
如果對錶的完整性沒有要求,或者兩張表的關聯字段取值相等,則使用 INNER JOIN

三個表的關聯查詢

案例:要求:查詢僱員編號,僱員姓名,僱員職位,所在部門名稱,工資等級。

SELECT e.`empno`, e.`ename`, e.`job`, d.`dname`, s.grade
FROM (emp e LEFT OUTER JOIN dept d ON e.`deptno` = d.`deptno`) 
	LEFT OUTER JOIN salgrade s ON e.`sal` BETWEEN s.`losal` AND s.hisal;

2.7 分組統計查詢

常見的統計函數

  • COUNT() : 計數,統計記錄數
SELECT COUNT(*) FROM emp;
  • SUM() : 求和
SELECT SUM(sal) 總工資 FROM emp;
  • AVG() : 求平均值
SELECT AVG(sal) 平均工資 FROM emp;
  • MAX() : 求最大值
SELECT MAX(sal) 最高工資 FROM emp;
  • MIN() : 求最小值
SELECT MIN(sal) 最高工資 FROM emp;

注意,COUNT(*)COUNT(字段)COUNT(DISTINCT 字段)的區別?

  • COUNT(*):統計除表中實際的數據量;
  • COUNT(字段):不會統計 NULL 值字段;
  • COUNT(DISTINCT 字段):消除重複數據後的統計結果。

分組統計

需要注意的是,有相同特徵的事物纔可以進行分組,對於數據庫來說,有重複數據纔可以進行分組。
分組統計查詢的語法如下:

SELECT [DISTINCT] *|列[別名],列[別名],... | 統計函數
FROM 數據表 [別名], 數據表 [別名],...
[WHERE 條件]
[GROUP BY 分組字段,分組字段,...]
[HAVING 分組後過濾條件]
[ORDER BY 字段 [ASC|DESC],字段 [ASC|DESC],...]
[LIMIT 開始行, 顯示行數]
  • 語句執行順序:1. FROM 2. WHERE 3. GROUP BY 4. HAVING 5. SELECT 6.ORDER BY 7. LIMIT
  • 統計查詢在Oracle數據庫中的限制:
    • 統計函數單獨使用時(沒有GROUP BY 子句),查詢語句中只能夠出現統計函數,不能夠出現其他字段;
    • 使用分組統計查詢時(有GROUP BY 子句),SELECT 子句中只能夠出現統計函數和分組字段,其他任何字段都不允許出現;

相關練習

  1. 要求:查詢出每個部門的名稱,部門人數,平均工資。
SELECT d.`dname`, COUNT(e.`empno`) 部門人數, AVG(e.`sal`) 平均工資
FROM emp e RIGHT OUTER JOIN dept d ON e.`deptno` = d.`deptno`
GROUP BY d.`dname`;
  1. 要求:查詢出每個部門的編號,名稱,位置,部門人數,平均工資。
SELECT d.`deptno`, d.`dname`, d.`loc`, COUNT(e.`empno`) 部門人數, AVG(e.`sal`) 平均工資
FROM emp e RIGHT OUTER JOIN dept d ON e.`deptno` = d.`deptno`
GROUP BY d.`deptno`, d.`dname`, d.`loc`;
  1. 要求:按照職位分組,統計每個職位的平均工資,要求顯示的是平均工資高於2000的職位信息。
SELECT job, AVG(sal)
FROM emp
GROUP BY job
HAVING AVG(sal) > 2000;

注意 WHEREHAVING 的區別:
WHERE 子句在分組之前執行,所以數據先經過 WHERE 子句篩選後才進行的分組,且 WHERE 子句不能使用統計函數。
HAVING 子句必須結合 GROUP BY 子句一起出現,是分組後的過濾,可以使用統計函數。
4. 要求:統計公司每個工資等級的人數,平均工資。

SELECT s.`grade`, COUNT(e.`empno`) 人數, AVG(e.`sal`) 平均工資
FROM emp e INNER JOIN salgrade s ON e.`sal` BETWEEN s.`losal` AND s.`hisal`
GROUP BY s.`grade`;

2.8 子查詢

子查詢是複雜查詢中最爲重要的。所謂子查詢,就是在一條查詢語句中嵌套若干條查詢。子查詢可以改善關聯查詢的性能。

子查詢可以嵌套在 SELECTFROMWHEREHAVING 子句中,嵌套的語句用 () 包裹起來。

根據子查詢語句返回的結果,其應該出現的位置及用法如下:

  • 子查詢返回的結果是 單行單列,也就是說,返回的結果就是一個數據,那麼它通常用於條件判斷,所以經常出現在 WHEREHAVING 子句中,這是直接使用它做條件判斷即可;

  • 子查詢返回的結果是 多行單列,也就是說,返回的結果是一組數據,那麼它通常出現在 WHERE 子句中,需要配合如下符號使用:

    • IN : 在指定的範圍內,可以配合 NOT 使用,表示不在範圍內。需要注意的是, NOT IN 的範圍中不能包含 NULL 值;
    • ANY : 指“任何”的意思,配合 >=< 使用;
      • =ANY : 功能和 IN 一樣
       SELECT * FROM emp
       WHERE sal = ANY(SELECT sal FROM emp WHERE job = 'manager')
      
      • >ANY : 比子查詢結果中的最小值大
       SELECT * FROM emp
       WHERE sal >ANY(SELECT sal FROM emp WHERE job = 'manager')
      
      • <ANY : 比子查詢結果中的最大值小
       SELECT * FROM emp
       WHERE sal >ANY(SELECT sal FROM emp WHERE job = 'manager')
      
    • ALL : 指“所有”的意思,同樣配合 >=< 使用;
      • >ALL : 比子查詢結果中的最大值大
      • <ALL : 比子查詢結果中的最小值小
  • 子查詢的結果返回多行多列,即,返回的結果是一個數據表,那麼它通常出現在 FROM 子句中,作爲一個虛擬表使用,最好配合別名使用。

相關練習

  1. 要求:查詢最早入職的僱員信息。
SELECT * 
FROM emp 
WHERE hiredate = (
	SELECT MIN(hiredate) 
	FROM emp);
  1. 要求:查詢與 Scott 從事同一工作,且工資相同的僱員信息。
SELECT * 
FROM emp
WHERE (job, sal) = (
	SELECT job, sal 
	FROM emp 
	WHERE ename = 'scott') AND ename <> 'scott';
  1. 要求:查詢出平均工資高於公司平均工資的職位名稱,職位人數,平均工資。
SELECT job, COUNT(empno), AVG(sal)
FROM emp
GROUP BY job
HAVING AVG(sal) > (SELECT AVG(sal) FROM emp);

2.9 複雜查詢綜合練習

  1. 要求:列出至少有一個員工的部門信息。
SELECT d.`deptno`, d.`dname`, d.`loc`, COUNT(e.`empno`)
FROM dept d LEFT OUTER JOIN emp e ON d.`deptno` = e.`deptno`
GROUP BY d.`deptno`
HAVING COUNT(e.`empno`) > 0;
  1. 要求:查詢出入職日期早於直接上級的所有員工的編號,姓名,部門名稱,上級姓名。
SELECT e.`empno`, e.`ename`,e.`hiredate`, d.`dname`, m.`ename`, m.`hiredate`
FROM (emp e LEFT OUTER JOIN dept d ON e.`deptno` = d.`deptno`)
	LEFT OUTER JOIN emp m ON e.`mgr` = m.`empno`
WHERE e.`hiredate` < m.`hiredate`;
  1. 要求:查詢出工資比 SMITH 高的所有員工信息。
SELECT * 
FROM emp
WHERE sal > (SELECT sal FROM emp WHERE ename = 'smith');
  1. 要求:查詢出所有辦事員(CLERK)的姓名及其所在部門名稱,部門人數。
SELECT e.ename, temp.tname, temp.count
FROM emp e LEFT OUTER JOIN (SELECT d.`deptno` tno, d.`dname` tname, COUNT(e.`empno`) COUNT
	     FROM dept d LEFT OUTER JOIN emp e ON d.`deptno` = e.`deptno`
	     GROUP BY d.`deptno`) temp ON e.`deptno` = temp.tno
WHERE e.`job` = 'CLERK';
  1. 要求:查詢出工資大於 1500 的各種工作,以及從事此工作的僱員人數。
SELECT job, COUNT(empno)
FROM emp
GROUP BY job
HAVING MIN(sal) > 1500;
  1. 要求:查詢出在 SALES 部門工作的員工姓名,工資。
SELECT e.ename, e.sal
FROM emp e LEFT OUTER JOIN dept d ON e.`deptno` = d.`deptno`
WHERE d.`dname` = 'SALES';
  1. 要求:查詢出工資高於公司平均工資的所有僱員姓名,所在部門,上級領導,工資等級,與具備此工資等級的僱員人數。
    分析步驟,首先查詢出工資高於公司平均工資的所有僱員姓名,所在部門,上級領導,工資等級
SELECT e.`ename`, d.`dname`, m.`ename`, s.`grade`
FROM (emp e LEFT OUTER JOIN dept d ON e.`deptno`=d.`deptno`) 
	INNER JOIN salgrade s ON e.`sal` BETWEEN s.`losal` AND s.`hisal`
		LEFT OUTER JOIN emp m ON e.`mgr` = m.`empno`
WHERE e.`sal` > (SELECT AVG(sal) FROM emp);

然後查詢出每個工資等級的人數:

SELECT s.`grade`, COUNT(e.`empno`)
FROM emp e INNER JOIN salgrade s ON e.`sal` BETWEEN s.`losal` AND s.`hisal`
GROUP BY s.`grade`;

最後在第一個查詢中再關聯第二個查詢的結果:

SELECT e.`ename`, d.`dname`, m.`ename`, s.`grade`, temp.count
FROM (emp e LEFT OUTER JOIN dept d ON e.`deptno`=d.`deptno`) 
	INNER JOIN salgrade s ON e.`sal` BETWEEN s.`losal` AND s.`hisal`
		LEFT OUTER JOIN emp m ON e.`mgr` = m.`empno`
			INNER JOIN (SELECT s.`grade` tgrade, COUNT(e.`empno`) COUNT
				    FROM emp e INNER JOIN salgrade s ON e.`sal` BETWEEN s.`losal` AND s.`hisal`
			            GROUP BY s.`grade`) temp ON s.`grade` = temp.tgrade
WHERE e.`sal` > (SELECT AVG(sal) FROM emp);
  1. 要求:查詢出各種工作的最低工資及從事此工作的僱員姓名。
SELECT temp.min, e.`ename`
FROM emp e INNER JOIN (SELECT job, MIN(sal) MIN
		       FROM emp
		       GROUP BY job) temp
WHERE e.`job` = temp.job AND e.`sal` = temp.min;
  1. 要求:查詢出各個部門辦事員(CLERK)的最低工資。
SELECT d.`dname`, MIN(e.`sal`)
FROM emp e LEFT OUTER JOIN dept d ON e.`deptno`=d.`deptno`
WHERE e.`job` = 'clerk'
GROUP BY d.`deptno`;
  1. 要求:查詢出部門名稱中有 s 的部門的僱員工資合計,及部門人數。
SELECT d.`dname`,SUM(e.`sal`), COUNT(e.`empno`)
FROM dept d LEFT OUTER JOIN emp e ON d.`deptno`=e.`deptno`
WHERE d.`dname` LIKE '%s%'
GROUP BY d.`dname`;
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章