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
不是NULL
,IFNULL()
返回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 NULL
、IS NOT NULL
;- 不能用邏輯運算符來進行空判斷,比如“comm != null”,正確的是 “comm IS NOT NULL”;
- 注意,對數據庫來說,0 和 null 是不一樣的概念;
- 基數範圍:
IN
、NOT IN
;- 表示在或者不在某幾個可選數值範圍之中;
字段 IN/NOT IN (數值, 數值,...)
- 注意:在使用 NOT IN 時,如果基數中包含了 NULL ,則無論有沒有滿足要求的數據,都不會被顯示,這是一種保護機制;
- 模糊查詢:
LIKE
字段 LIKE '匹配的關鍵字'
;_
:表示匹配任意 一個 字符%
:表示匹配任意 0個,1個,或多個關鍵字;- 如果不使用任何通配符,則表示精確匹配。
- 關係運算符:
相關練習
- 要求:查詢出所有銷售人員(SALESMAN)中工資高於 1200 的僱員信息。
SELECT * FROM emp WHERE job = 'salesman' AND sal > 1200;
- 要求:查詢出工資在 1200 ~ 3000 之間的僱員信息。
SELECT * FROM emp WHERE sal BETWEEN 1200 AND 3000;
- 要求:查詢出所有在 1981 年僱傭的僱員信息。
SELECT * FROM emp WHERE hiredate BETWEEN '1981-01-01' AND '1981-12-31';
- 要求:查詢所有領取佣金的僱員,即 comm 不爲 null。
SELECT * FROM emp WHERE comm IS NOT NULL;
- 要求:查詢出僱員編號爲 7369,7566,7839,8899 的僱員。
SELECT * FROM emp WHERE empno IN (7369,7566,7839,8899);
- 要求:查詢出姓名中第二個字母是'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
表示降序。
相關練習
- 要求:查詢出所有僱員的信息,結果按照工資由高到低排序,如果工資相同,則按照入職日期從早到晚排序。
SELECT * FROM emp ORDER BY sal DESC, hiredate;
- 要求:查詢出所有僱員的信息,按照年薪排序。
SELECT * FROM emp ORDER BY sal*12 ;
2.5 思考題
- 要求:查詢部門 30 中的所有員工。
select * from emp where deptno = 30;
- 要求:查詢所有辦事員(CLERK)的姓名,編號,部門編號。
select ename, empno,job, deptno from emp where job = 'CLERK';
- 要求:查詢出佣金高於工資 60 % 的僱員。
select * from emp where comm > sal*0.6
- 要求:查詢出部門 10 中所有的經理 和 部門 20 中所有的辦事員。
select * from emp where (deptno = 10 and job = 'manager') or (deptno = 20 and job = 'CLERK');
- 要求:查詢出部門 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);
- 要求:查詢出收入組成中有佣金的員工的不同工作。
select distinct job from emp where comm is not null;
- 要求:查詢出收入組成中無佣金 或者佣金收入低於 100 的僱員信息。
select * from emp where comm is null or comm < 100;
- 要求:查詢姓名中沒有 “R” 的員工姓名。
select ename from emp where ename not like '%R%';
- 要求:查詢姓名中有 “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
子句中指定關聯字段,則查詢的結果將會是兩個數據表的"笛卡兒積",其實指定了關聯字段,這個"笛卡兒積"依然存在,只是被過濾掉了。所以,在數據量比較大的情況下,多表關聯查詢的效率是比較差的。
相關練習
- 要求:查詢每個僱員的編號,姓名,職位,工資,部門名稱,部門位置。
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;
- 要求:查詢每個僱員的編號,姓名,職位,工資,入職日期,工資等級。
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 暫不支持,需要使用 查詢結果連接符 UNION
,UNION
操作會將兩個 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
子句中只能夠出現統計函數和分組字段,其他任何字段都不允許出現;
- 統計函數單獨使用時(沒有
相關練習
- 要求:查詢出每個部門的名稱,部門人數,平均工資。
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`;
- 要求:查詢出每個部門的編號,名稱,位置,部門人數,平均工資。
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`;
- 要求:按照職位分組,統計每個職位的平均工資,要求顯示的是平均工資高於2000的職位信息。
SELECT job, AVG(sal) FROM emp GROUP BY job HAVING AVG(sal) > 2000;
注意 WHERE
和 HAVING
的區別: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 子查詢
子查詢是複雜查詢中最爲重要的。所謂子查詢,就是在一條查詢語句中嵌套若干條查詢。子查詢可以改善關聯查詢的性能。
子查詢可以嵌套在 SELECT
、FROM
、WHERE
、HAVING
子句中,嵌套的語句用 ()
包裹起來。
根據子查詢語句返回的結果,其應該出現的位置及用法如下:
-
子查詢返回的結果是 單行單列,也就是說,返回的結果就是一個數據,那麼它通常用於條件判斷,所以經常出現在
WHERE
、HAVING
子句中,這是直接使用它做條件判斷即可; -
子查詢返回的結果是 多行單列,也就是說,返回的結果是一組數據,那麼它通常出現在 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
子句中,作爲一個虛擬表使用,最好配合別名使用。
相關練習
- 要求:查詢最早入職的僱員信息。
SELECT * FROM emp WHERE hiredate = ( SELECT MIN(hiredate) FROM emp);
- 要求:查詢與 Scott 從事同一工作,且工資相同的僱員信息。
SELECT * FROM emp WHERE (job, sal) = ( SELECT job, sal FROM emp WHERE ename = 'scott') AND ename <> 'scott';
- 要求:查詢出平均工資高於公司平均工資的職位名稱,職位人數,平均工資。
SELECT job, COUNT(empno), AVG(sal) FROM emp GROUP BY job HAVING AVG(sal) > (SELECT AVG(sal) FROM emp);
2.9 複雜查詢綜合練習
- 要求:列出至少有一個員工的部門信息。
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;
- 要求:查詢出入職日期早於直接上級的所有員工的編號,姓名,部門名稱,上級姓名。
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`;
- 要求:查詢出工資比 SMITH 高的所有員工信息。
SELECT * FROM emp WHERE sal > (SELECT sal FROM emp WHERE ename = 'smith');
- 要求:查詢出所有辦事員(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';
- 要求:查詢出工資大於 1500 的各種工作,以及從事此工作的僱員人數。
SELECT job, COUNT(empno) FROM emp GROUP BY job HAVING MIN(sal) > 1500;
- 要求:查詢出在 SALES 部門工作的員工姓名,工資。
SELECT e.ename, e.sal FROM emp e LEFT OUTER JOIN dept d ON e.`deptno` = d.`deptno` WHERE d.`dname` = 'SALES';
- 要求:查詢出工資高於公司平均工資的所有僱員姓名,所在部門,上級領導,工資等級,與具備此工資等級的僱員人數。
分析步驟,首先查詢出工資高於公司平均工資的所有僱員姓名,所在部門,上級領導,工資等級
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);
- 要求:查詢出各種工作的最低工資及從事此工作的僱員姓名。
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;
- 要求:查詢出各個部門辦事員(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`;
- 要求:查詢出部門名稱中有 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`;