文章目录

  • 一、查询
  • 1、基本查询
  • (1)基本用法
  • (2)过滤数据WHERE
  • (3)排序ORDER BY
  • (4)字符匹配查询LIKE
  • (5)查询结果不重复DISTINCT
  • (6)分组查询GROUP BY
  • (7)限制查询结果数量LIMIT
  • 2、使用集合函数查询
  • (1)计算表中行的总数COUNT()
  • (2)计算指定列值的总和SUM()
  • (3)计算指定列的平均值AVG()
  • (4)返回指定列的最大值MAX() / 最小值MIN()
  • 3、连接查询
  • (1)内连接查询
  • (2)外连接查询
  • (3)复合条件连接查询
  • 4、子查询
  • (1)带ANY/SOME和ALL关键字的子查询
  • (2)带EXISTS/NOT EXISTS关键字的子查询
  • (3)使用操作符的子查询
  • 5、合并查询结果
  • 二、*插入*
  • 1、手动插入数据
  • 2、将查询结果插入表中
  • 三、更新数据
  • 四、删除数据
  • 五、为表添加计算列


一、查询

MySQL的基本查询语句位SELECT语句,其语法规则如下

SELECT <字段列表>
	[FROM <表名>]							# 选择数据的来源
	[WHERE <表达式>]					 # 按某个条件过滤查询到的数据
	[GROUP BY <分组表达式>]	  # 按某个条件对数据分组
	[HAVING <表达式>]				 # 对分组后的数据按某个条件进行过滤
	[ORDER BY <字段名>]			 # 以某个变量为基准排序
	[LIMIT <数量>];					  # 限制打印的数据量
  • SELECT相当于print语句,即选择查询的内容并打印
  • 字段列表相当于变量,用于选择查询的内容

1、基本查询

(1)基本用法

mysql> SELECT 3+5 AS sum;			# 打印3+5,AS用于给前面的变量起变量名
+-----+
| sum |
+-----+
|   8 |
+-----+
1 row in set (0.00 sec)
mysql> SELECT * 
			 FROM departments  
			 LIMIT 10;		# 打印数据表departments中的所有数据,限制输出10行
+---------+--------------------+
| dept_no | dept_name          |
+---------+--------------------+
| d009    | Customer Service   |
| d005    | Development        |
| d002    | Finance            |
| d003    | Human Resources    |
| d001    | Marketing          |
| d004    | Production         |
| d006    | Quality Management |
| d008    | Research           |
| d007    | Sales              |
+---------+--------------------+
9 rows in set (0.00 sec)
mysql> SELECT dept_no AS a, dept_name AS b 
			 FROM departments  
			 LIMIT 10;
+------+--------------------+
| a    | b                  |
+------+--------------------+
| d009 | Customer Service   |
| d005 | Development        |
| d002 | Finance            |
| d003 | Human Resources    |
| d001 | Marketing          |
| d004 | Production         |
| d006 | Quality Management |
| d008 | Research           |
| d007 | Sales              |
+------+--------------------+
9 rows in set (0.00 sec)

(2)过滤数据WHERE

mysql> SELECT salary 
			 FROM salaries 
			 WHERE salary>60000 AND salary<70000 		# 对查到的数据按某种条件过滤
			 LIMIT 10;															
+--------+
| salary |
+--------+
|  60117 |
|  62102 |
|  66074 |
|  66596 |
|  66961 |
|  65828 |
|  65909 |
|  67534 |
|  69366 |
|  60770 |
+--------+
10 rows in set (0.00 sec)
  • IN操作符常用来与关键字的查找
  • BETWEEN AND常用于范围查找
  • ANDOR用于多条件查询,且AND的优先级高于OR
  • INOR的功能相同,但是IN的执行速度快于OR

(3)排序ORDER BY

mysql> SELECT salary 
       FROM salaries 
			 ORDER BY salary 							 # ORDER BY子语句默认按升序(ASC)排序
			 LIMIT 10;		
+--------+
| salary |
+--------+
|  38623 |
|  38735 |
|  38786 |
|  38812 |
|  38836 |
|  38849 |
|  38850 |
|  38851 |
|  38859 |
|  38864 |
+--------+
10 rows in set (0.85 sec)

mysql> SELECT salary 
			 FROM salaries 
			 ORDER BY salary DESC 					# 指定按照降序排序
			 LIMIT 10;		
+--------+
| salary |
+--------+
| 158220 |
| 157821 |
| 156286 |
| 155709 |
| 155513 |
| 155377 |
| 155190 |
| 154888 |
| 154885 |
| 154459 |
+--------+
10 rows in set (0.82 sec)
mysql> SELECT * 
			 FROM salaries 
			 ORDER BY salary DESC, emp_no 		# 可以指定多个排序的基准
			 LIMIT 10;
+--------+--------+------------+------------+
| emp_no | salary | from_date  | to_date    |
+--------+--------+------------+------------+
|  43624 | 158220 | 2002-03-22 | 9999-01-01 |
|  43624 | 157821 | 2001-03-22 | 2002-03-22 |
| 254466 | 156286 | 2001-08-04 | 9999-01-01 |
|  47978 | 155709 | 2002-07-14 | 9999-01-01 |
| 253939 | 155513 | 2002-04-11 | 9999-01-01 |
| 109334 | 155377 | 2000-02-12 | 2001-02-11 |
| 109334 | 155190 | 2002-02-11 | 9999-01-01 |
| 109334 | 154888 | 2001-02-11 | 2002-02-11 |
| 109334 | 154885 | 1999-02-12 | 2000-02-12 |
|  80823 | 154459 | 2002-02-22 | 9999-01-01 |
+--------+--------+------------+------------+
10 rows in set (0.95 sec)
  • 多排序时,先按照第一个基准进行第一次排序
  • 第一次排序完成后,再按照第二个基准对第一次排序的相同结果排序,依此类推
  • 默认升序,要降序排序必须指定DESC

(4)字符匹配查询LIKE

MySQL可以使用通配符来进行匹配查找,关键字为LIKE

  • %:匹配任意长度的字符(包括长度为0的字符)
  • _:一次匹配一个字符
  • 使用BINARY区分大小写
mysql> SELECT first_name 
			 FROM employees 
			 WHERE first_name LIKE BINARY "%A%"		# 查询first_name中包含A的数据
			 																			# 去掉BINARY,就不区分大小写(如果建表时没有区分大写)
			 LIMIT 5;
+------------+
| first_name |
+------------+
| Anneke     |
| Arif       |
| Alain      |
| Adamantios |
| Alejandro  |
+------------+
5 rows in set (0.00 sec)

mysql> SELECT first_name 
			 FROM employees 
			 WHERE first_name LIKE BINARY "_a%" 	# 查询first_name中第二个字母为a的数据
			 LIMIT 5;
+------------+
| first_name |
+------------+
| Parto      |
| Saniya     |
| Mary       |
| Patricio   |
| Kazuhito   |
+------------+
5 rows in set (0.00 sec)

(5)查询结果不重复DISTINCT

mysql> SELECT emp_no 
			 FROM salaries 
			 ORDER BY emp_no 
			 LIMIT 10;
+--------+
| emp_no |
+--------+
|  10001 |
|  10001 |
|  10001 |
|  10001 |
|  10001 |
|  10001 |
|  10001 |
|  10001 |
|  10001 |
|  10001 |
+--------+
10 rows in set (0.00 sec)

mysql> SELECT DISTINCT emp_no 		# 使用DISTINCT关键字对指定字段去重
			 FROM salaries  
			 ORDER BY emp_no 
			 LIMIT 10;
+--------+
| emp_no |
+--------+
|  10001 |
|  10002 |
|  10003 |
|  10004 |
|  10005 |
|  10006 |
|  10007 |
|  10008 |
|  10009 |
|  10010 |
+--------+
10 rows in set (0.00 sec)
  • 直接使用DISTINCT只能返回指定的去重的一列,不能返回其它列
  • 想要返回去重的多列数据,可以使用分组
mysql> SELECT emp_no, COUNT(*) AS total 	# COUNT为函数,用于计算行的总数
			 FROM salaries   
			 GROUP BY emp_no 						# 按照emp_no分组
			 ORDER BY total DESC 
			 LIMIT 10;
+--------+-------+
| emp_no | total |
+--------+-------+
| 279953 |    18 |
| 239758 |    18 |
| 292257 |    18 |
| 235678 |    18 |
| 295842 |    18 |
| 470102 |    18 |
|  26608 |    18 |
|  16431 |    18 |
| 251839 |    18 |
| 105540 |    18 |
+--------+-------+
10 rows in set (0.68 sec)

上面的语句是查询按照emp_no分组,每一个emp_no的总数

(6)分组查询GROUP BY

  • 基本使用:按照某一字段分组
mysql> SELECT id, COUNT(*) AS total 
			 FROM groupTEST 
			 GROUP BY id;				# 按照id分组,所有id相同的分为一组
+------+-------+
| id   | total |
+------+-------+
|    1 |     4 |
|    2 |     2 |
|    3 |     6 |
+------+-------+
3 rows in set (0.00 sec)

mysql> SELECT id, GROUP_CONCAT(name) 		# 将id相同的name通过分组拼接在一起
			 FROM groupTEST 
			 GROUP BY id;
+------+--------------------------+
| id   | GROUP_CONCAT(name)       |
+------+--------------------------+
|    1 | Xiong,Wang,Li,Xiao       |
|    2 | Xiong,Li                 |
|    3 | Li,Xiao,Wang,Xue,Xue,Xue |
+------+--------------------------+
3 rows in set (0.00 sec)
  • 使用HAVING过滤数据
  • WHERE是在分组前过滤数据,HAVING是对分组后的数据进行过滤
mysql> SELECT name, COUNT(*) AS total 
			 FROM groupTEST 
			 GROUP BY name;
+-------+-------+
| name  | total |
+-------+-------+
| Li    |     3 |
| Wang  |     2 |
| Xiao  |     2 |
| Xiong |     2 |
| Xue   |     3 |
+-------+-------+
5 rows in set (0.00 sec)

mysql> SELECT name, COUNT(*) AS total 
			 FROM groupTEST 
			 GROUP BY name HAVING total<3;
+-------+-------+
| name  | total |
+-------+-------+
| Wang  |     2 |
| Xiao  |     2 |
| Xiong |     2 |
+-------+-------+
3 rows in set (0.00 sec)
  • 使用WITH ROLLUP统计记录数量
  • ROLLUPORDER BY互斥
mysql> SELECT name, COUNT(*) AS total 
			 FROM groupTEST 
			 GROUP BY name WITH ROLLUP;			# 使用该关键字后,会在表中最后一行显示统计的总数
+-------+-------+
| name  | total |
+-------+-------+
| Li    |     3 |
| Wang  |     2 |
| Xiao  |     2 |
| Xiong |     2 |
| Xue   |     3 |
| NULL  |    12 |
+-------+-------+
6 rows in set (0.00 sec)
  • 多字段分组查询
mysql> SELECT id, name, COUNT(*) AS total 
			 FROM groupTEST 
			 GROUP BY id, name;			# 先对第一个字段分组,再对第二个字段分组,COUNT计算的是最后一个分组
+------+-------+-------+
| id   | name  | total |
+------+-------+-------+
|    1 | Li    |     1 |
|    1 | Wang  |     1 |
|    1 | Xiao  |     1 |
|    1 | Xiong |     1 |
|    2 | Li    |     1 |
|    2 | Xiong |     1 |
|    3 | Li    |     1 |
|    3 | Wang  |     1 |
|    3 | Xiao  |     1 |
|    3 | Xue   |     3 |
+------+-------+-------+
10 rows in set (0.00 sec)

(7)限制查询结果数量LIMIT

LIMIT可以限制输出结果的位置与数量,基本语法如下

LIMIT [位置偏移量,] 行数
mysql> SELECT * FROM salaries 
			 ORDER BY salary 
			 LIMIT 10;								# 输出结果前十行
+--------+--------+------------+------------+
| emp_no | salary | from_date  | to_date    |
+--------+--------+------------+------------+
| 253406 |  38623 | 2002-02-20 | 9999-01-01 |
|  49239 |  38735 | 1996-09-17 | 1997-09-17 |
| 281546 |  38786 | 1996-11-13 | 1997-06-26 |
|  15830 |  38812 | 2001-03-12 | 2002-03-12 |
|  64198 |  38836 | 1989-10-20 | 1990-10-20 |
| 475254 |  38849 | 1993-06-04 | 1994-06-04 |
|  50419 |  38850 | 1996-09-22 | 1997-09-22 |
|  34707 |  38851 | 1990-10-03 | 1991-10-03 |
|  49239 |  38859 | 1995-09-18 | 1996-09-17 |
| 274049 |  38864 | 1996-09-01 | 1997-09-01 |
+--------+--------+------------+------------+
10 rows in set (2.08 sec)

mysql> SELECT * FROM salaries 
			 ORDER BY salary 
			 LIMIT 2, 10;							# 输出从第2行开始的10行
+--------+--------+------------+------------+
| emp_no | salary | from_date  | to_date    |
+--------+--------+------------+------------+
| 281546 |  38786 | 1996-11-13 | 1997-06-26 |
|  15830 |  38812 | 2001-03-12 | 2002-03-12 |
|  64198 |  38836 | 1989-10-20 | 1990-10-20 |
| 475254 |  38849 | 1993-06-04 | 1994-06-04 |
|  50419 |  38850 | 1996-09-22 | 1997-09-22 |
|  34707 |  38851 | 1990-10-03 | 1991-10-03 |
|  49239 |  38859 | 1995-09-18 | 1996-09-17 |
| 274049 |  38864 | 1996-09-01 | 1997-09-01 |
| 473390 |  38872 | 1995-03-20 | 1995-09-22 |
|  12444 |  38874 | 1990-08-15 | 1991-08-15 |
+--------+--------+------------+------------+
10 rows in set (0.96 sec)
  • LIMIT 3, 4LIMIT 3 OFFSET 4效果一样

2、使用集合函数查询

MySQL提供一些查询功能,可以对获取的数据进行分析和报告

(1)计算表中行的总数COUNT()

COUNT()返回结果中指定列的行数

  • COUNT(*)计算表中总的行数,无论是有数值还是空值
  • COUNT(字段名)会忽略空值
mysql> SELECT COUNT(*) 
			 FROM salaries 
			 WHERE salary BETWEEN 50000 AND 70000;
+----------+
| COUNT(*) |
+----------+
|  1258826 |
+----------+
1 row in set (0.61 sec)

(2)计算指定列值的总和SUM()

mysql> SELECT emp_no, salary 
			 FROM salaries 
			 WHERE emp_no BETWEEN 10000 AND 10001;
+--------+--------+
| emp_no | salary |
+--------+--------+
|  10001 |  60117 |
|  10001 |  62102 |
|  10001 |  66074 |
|  10001 |  66596 |
|  10001 |  66961 |
|  10001 |  71046 |
|  10001 |  74333 |
|  10001 |  75286 |
|  10001 |  75994 |
|  10001 |  76884 |
|  10001 |  80013 |
|  10001 |  81025 |
|  10001 |  81097 |
|  10001 |  84917 |
|  10001 |  85112 |
|  10001 |  85097 |
|  10001 |  88958 |
+--------+--------+
17 rows in set (0.00 sec)

mysql> SELECT SUM(salary) 
			 FROM salaries 
			 WHERE emp_no BETWEEN 10000 AND 10001;
+-------------+
| SUM(salary) |
+-------------+
|     1281612 |
+-------------+
1 row in set (0.00 sec)

(3)计算指定列的平均值AVG()

mysql> SELECT emp_no, AVG(salary) AS avg_salary 
			 FROM salaries 
			 GROUP BY emp_no 
			 ORDER BY avg_salary 
			 LIMIT 10;
+--------+------------+
| emp_no | avg_salary |
+--------+------------+
|  15830 | 39299.5000 |
| 253406 | 39332.7500 |
| 473390 | 39372.5000 |
| 281546 | 39417.2500 |
| 466226 | 39442.7500 |
| 401786 | 39453.7500 |
| 245832 | 39515.2500 |
| 230890 | 39520.0000 |
| 496197 | 39573.3333 |
| 496848 | 39584.0000 |
+--------+------------+
10 rows in set (1.08 sec)

(4)返回指定列的最大值MAX() / 最小值MIN()

  • MAXMIN可以查找数字和日期
  • 还可以查找字符类型的最大值最小值,根据ASCII查找
mysql> SELECT MAX(salary) 
			 FROM salaries;
+-------------+
| MAX(salary) |
+-------------+
|      158220 |
+-------------+
1 row in set (0.60 sec)

mysql> SELECT MIN(salary) 
			 FROM salaries;
+-------------+
| MIN(salary) |
+-------------+
|       38623 |
+-------------+
1 row in set (0.59 sec)

mysql> SELECT MIN(birth_date) 
			 FROM employees;
+-----------------+
| MIN(birth_date) |
+-----------------+
| 1952-02-01      |
+-----------------+
1 row in set (0.18 sec)

mysql> SELECT MAX(birth_date) 
			 FROM employees;
+-----------------+
| MAX(birth_date) |
+-----------------+
| 1965-02-01      |
+-----------------+
1 row in set (0.08 sec)

3、连接查询

  • 在查询数据时把多张表联合起来查询,这种多表联合查询称为连接查询或跨表查询
  • 举个例子:表emp有一个字段emp_no(3行数据),表dept有一个字段dept_no(4行数据),当无任何约束条件同时查询员工和部门(SELECT emp_no, dept_no FROM emp, dept)时,会得到12行数据(3*4),称为笛卡尔积
  • 连接查询可以用WHERE子语句做到,但是WHERE子语句在某些时候会影响查询的性能

创建数据库emp(员工表)、dept(部门表)、salaries(薪水表)

mysql> CREATE TABLE emp (
  		     emp_no INT AUTO_INCREMENT KEY, 
  				 name VARCHAR(20) NOT NULL, 
  				 dept_no INT, 
  				 salary INT);
Query OK, 0 rows affected (0.04 sec)

mysql> CREATE TABLE dept (
  		     dept_no INT KEY, 
  				 dname VARCHAR(20));
Query OK, 0 rows affected (0.04 sec)

mysql> CREATE TABLE salaries (
  				 low INT, 
  				 high INT, 
  				 level INT);
Query OK, 0 rows affected (0.04 sec)
mysql> INSERT INTO emp VALUES
    -> (1, "Xiong", 101, 1000),
    -> (2, "Wang", 101, 1200),
    -> (3, "Li", 103, 1500),
    -> (4, "Zhao", 104, 2300),
    -> (5, "Xiao", 104, 2000),
    -> (6, "Hu", 105, 2100);
Query OK, 6 rows affected (0.02 sec)
Records: 6  Duplicates: 0  Warnings: 0

mysql> INSERT INTO dept VALUES
    -> (101, "部门1"),
    -> (102, "部门2"),
    -> (103, "部门3"),
    -> (104, "部门4"),
    -> (105, "部门5");
Query OK, 5 rows affected (0.02 sec)
Records: 5  Duplicates: 0  Warnings: 0

mysql> INSERT INTO salaries VALUES
    -> (1000, 1500, 1),
    -> (1501, 2000, 2),
    -> (2001, 2500, 3),
    -> (2501, 3000, 4),
    -> (3001, 3055, 5);
Query OK, 5 rows affected (0.01 sec)
Records: 5  Duplicates: 0  Warnings: 0

(1)内连接查询

  • 内连接即完全匹配,只显示匹配的数据
  • 内连接分为等值连接、非等值连接和自连接
  • 自连接:即把一张表看作为不同的表来使用连接查询

等值连接

mysql> SELECT e.emp_no, e.name, d.dept_no, d.dname 
			 FROM emp e 								# AS可省略
			 INNER JOIN dept d 
			 ON e.dept_no=d.dept_no;
+--------+-------+---------+---------+
| emp_no | name  | dept_no | dname   |
+--------+-------+---------+---------+
|      1 | Xiong |     101 | 部门1   |
|      2 | Wang  |     101 | 部门1   |
|      3 | Li    |     103 | 部门3   |
|      4 | Zhao  |     104 | 部门4   |
|      5 | Xiao  |     104 | 部门4   |
|      6 | Hu    |     105 | 部门5   |
+--------+-------+---------+---------+
6 rows in set (0.00 sec)

非等值连接

mysql> SELECT e.name, e.salary, s.level 
			 FROM emp e 
			 INNER JOIN salaries s 
			 ON e.salary BETWEEN s.low AND s.high;
+-------+--------+-------+
| name  | salary | level |
+-------+--------+-------+
| Xiong |   1000 |     1 |
| Wang  |   1200 |     1 |
| Li    |   1500 |     1 |
| Zhao  |   2300 |     3 |
| Xiao  |   2000 |     2 |
| Hu    |   2100 |     3 |
+-------+--------+-------+
6 rows in set (0.01 sec)

(2)外连接查询

  • 外连接就是除了显示内连接的匹配数据以外,还将一张表的所有数据无条件显示,另一张表没有匹配记录的以NULL值填充
  • 外连接分为左外连接和右外连接(这两个本质上是等价的)
mysql> SELECT e.name, e.salary, s.level     			# 右外连接
			 FROM emp e 
			 RIGHT OUTER JOIN salaries s 
			 ON e.salary BETWEEN s.low AND s.high;
+-------+--------+-------+
| name  | salary | level |
+-------+--------+-------+
| Xiong |   1000 |     1 |
| Wang  |   1200 |     1 |
| Li    |   1500 |     1 |
| Zhao  |   2300 |     3 |
| Xiao  |   2000 |     2 |
| Hu    |   2100 |     3 |
| NULL  |   NULL |     4 |
| NULL  |   NULL |     5 |
+-------+--------+-------+
8 rows in set (0.00 sec)

mysql> SELECT e.name, e.salary, s.level 					# 左外连接
			 FROM salaries s 
			 LEFT OUTER JOIN emp e 
			 ON e.salary BETWEEN s.low AND s.high;
+-------+--------+-------+
| name  | salary | level |
+-------+--------+-------+
| Xiong |   1000 |     1 |
| Wang  |   1200 |     1 |
| Li    |   1500 |     1 |
| Zhao  |   2300 |     3 |
| Xiao  |   2000 |     2 |
| Hu    |   2100 |     3 |
| NULL  |   NULL |     4 |
| NULL  |   NULL |     5 |
+-------+--------+-------+
8 rows in set (0.00 sec)

(3)复合条件连接查询

mysql> SELECT e.name, e.salary, s.level 
			 FROM emp e 
			 INNER JOIN salaries s 
			 ON e.salary BETWEEN s.low AND s.high AND s.level<=2;
+-------+--------+-------+
| name  | salary | level |
+-------+--------+-------+
| Xiong |   1000 |     1 |
| Wang  |   1200 |     1 |
| Li    |   1500 |     1 |
| Xiao  |   2000 |     2 |
+-------+--------+-------+
4 rows in set (0.00 sec)

4、子查询

  • 子查询即嵌套查询,内层查询作为外层查询的过滤条件
  • 子查询可以添加到SELECT、UPDATE、DELETE语句中

创建两张表为示例

mysql> CREATE TABLE t1 (n1 INT);
Query OK, 0 rows affected (0.14 sec)

mysql> CREATE TABLE t2 (n2 INT);
Query OK, 0 rows affected (0.08 sec)

mysql> INSERT INTO t1 VALUES (10), (15), (20), (25);
Query OK, 4 rows affected (0.02 sec)
Records: 4  Duplicates: 0  Warnings: 0

mysql> INSERT INTO t2 VALUES (11), (12), (21), (23);
Query OK, 4 rows affected (0.02 sec)
Records: 4  Duplicates: 0  Warnings: 0

(1)带ANY/SOME和ALL关键字的子查询

  • ANY和SOME关键字等效,都是只要满足一个条件即可
  • 下例中,t1的n1跟子查询的结果n2一一比较,只要n1大于n2中的任意一个就满足条件
mysql> SELECT n1 FROM t1
    -> WHERE n1>ANY
    -> (SELECT n2 FROM t2);
+------+
| n1   |
+------+
|   15 |
|   20 |
|   25 |
+------+
3 rows in set (0.00 sec)
# n2为11、12、21、22,n1为10、15、20、25,只有10不满足条件
# 15、20、25均大于11、12、21、22中的任意一个
  • ALL关键字于ANY相反,需要满足所有条件
mysql> SELECT n1 FROM t1
    -> WHERE n1>ALL
    -> (SELECT n2 FROM t2);
+------+
| n1   |
+------+
|   25 |
+------+
1 row in set (0.00 sec)
# n2为11、12、21、22,n1为10、15、20、25,只有25满足条件
# 只有25满足大于11、12、21、22的所有条件

(2)带EXISTS/NOT EXISTS关键字的子查询

  • EXISTS关键字返回内层查询的结果是否为空,若内层查询至少有一个结果,则返回TRUE,反之返回FALSE;当返回FALSE时,外层查询不生效
  • NOT EXISTS效果于EXISTS相反

下例中,t2的n2均小于30

mysql> SELECT * FROM t1
    -> WHERE EXISTS
    -> (SELECT n2 FROM t2 WHERE n2 > 30);
Empty set (0.00 sec)

mysql> SELECT * FROM t1
    -> WHERE NOT EXISTS
    -> (SELECT n2 FROM t2 WHERE n2 > 30);
+------+
| n1   |
+------+
|   10 |
|   15 |
|   20 |
|   25 |
+------+
4 rows in set (0.00 sec)

(3)使用操作符的子查询

mysql> SELECT n1 FROM t1
    -> WHERE n1 IN
    -> (SELECT n2 FROM t2 WHERE n2<15);
Empty set (0.00 sec)

5、合并查询结果

  • 使用UNION/UNION ALL关键字可以合并多条SELECT查询的结果
  • 加上ALL,不会删除重复行,更节省资源
mysql> CREATE TABLE fruits (id INT, price INT, name VARCHAR(10));
Query OK, 0 rows affected (0.11 sec)

mysql> INSERT INTO fruits VALUES
    -> (1, 100, "苹果"),
    -> (2, 102, "梨子"),
    -> (3, 120, "桃子"),
    -> (4, 121, "草莓");
Query OK, 4 rows affected (0.01 sec)
Records: 4  Duplicates: 0  Warnings: 0

# 查询fruits表中price在100~110之间及id为4的水果的信息
mysql> SELECT id, name 
    -> FROM fruits
    -> WHERE fruits.price BETWEEN 100 AND 110
    -> UNION ALL
    -> SELECT id, name
    -> FROM fruits
    -> WHERE fruits.id=4;
+------+--------+
| id   | name   |
+------+--------+
|    1 | 苹果   |
|    2 | 梨子   |
|    4 | 草莓   |
+------+--------+
3 rows in set (0.00 sec)

二、插入

1、手动插入数据

基本语法如下

INSERT INTO <表名> [字段名] VALUES <列值 [, ...]>;
  • 如果不指定字段名,则插入时必须按照定义时的顺序插入数据
mysql> CREATE TABLE t1 
			 (a INT, b INT);
Query OK, 0 rows affected (0.06 sec)

mysql> CREATE TABLE t2 
			 (a INT, b INT, c INT);
Query OK, 0 rows affected (0.04 sec)

mysql> INSERT INTO t1 VALUES
    -> (100, 200),
    -> (101, 300),
    -> (102, 400);
Query OK, 3 rows affected (0.01 sec)
Records: 3  Duplicates: 0  Warnings: 0
# Records为插入的条数纪录
# Duplicates为被忽略的纪录
# Warnings表明有问题的数据值

mysql> INSERT INTO t2 VALUES
    -> (103, 1, 500),
    -> (104, 2, 600),
    -> (105, 3, 700);
Query OK, 3 rows affected (0.01 sec)
Records: 3  Duplicates: 0  Warnings: 0
  • 指定字段名插入,可以不按顺序插入,也可以只插入部分字段
mysql> INSERT INTO t2 (a, c) 
 		->	VALUES
    -> (1, 100),
    -> (2, 200);
Query OK, 2 rows affected (0.03 sec)
Records: 2  Duplicates: 0  Warnings: 0

mysql> SELECT * FROM t2;      # 对未插入值的列默认为NULL
+------+------+------+
| a    | b    | c    |
+------+------+------+
|    1 | NULL |  100 |
|    2 | NULL |  200 |
+------+------+------+
2 rows in set (0.00 sec)
  • 单条插入多行数据的语句等于多行插入单条数据的语句,但是单条语句效率比多条语句高

2、将查询结果插入表中

  • 使用SELECT和INSERT语句的组合可以将查询的结果插入表中
mysql> INSERT INTO t1 (a, b)
    -> SELECT a, c FROM t2;
Query OK, 2 rows affected (0.02 sec)
Records: 2  Duplicates: 0  Warnings: 0

mysql> SELECT * FROM t1;
+------+------+
| a    | b    |
+------+------+
|    1 |  100 |
|    2 |  200 |
+------+------+
2 rows in set (0.00 sec)
  • 也可以不指定字段名插入,则按照表的列定义顺序一一对应插入
mysql> INSERT INTO t2
    -> SELECT * FROM t2;
Query OK, 2 rows affected (0.02 sec)
Records: 2  Duplicates: 0  Warnings: 0

mysql> SELECT * FROM t2;
+------+------+------+
| a    | b    | c    |
+------+------+------+
|    1 | NULL |  100 |
|    2 | NULL |  200 |
|    1 | NULL |  100 |
|    2 | NULL |  200 |
+------+------+------+
4 rows in set (0.00 sec)

三、更新数据

  • 更新表可以更新特定的行,或者更新所有行
mysql> SELECT * FROM fruits;
+------+-------+--------+
| id   | price | name   |
+------+-------+--------+
|    1 |   100 | 苹果   |
|    2 |   102 | 梨子   |
|    3 |   120 | 桃子   |
|    4 |   121 | 草莓   |
+------+-------+--------+
4 rows in set (0.00 sec)

mysql> UPDATE fruits 
			 SET id=1,price=1000,name="车厘子" 
			 WHERE id=1;
Query OK, 1 row affected (0.01 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> SELECT * FROM fruits;
+------+-------+-----------+
| id   | price | name      |
+------+-------+-----------+
|    1 |  1000 | 车厘子    |
|    2 |   102 | 梨子      |
|    3 |   120 | 桃子      |
|    4 |   121 | 草莓      |
+------+-------+-----------+
4 rows in set (0.00 sec)

mysql> UPDATE fruits 
			 SET id=1,price=1000,name="车厘子";
Query OK, 3 rows affected (0.01 sec)
Rows matched: 4  Changed: 3  Warnings: 0

mysql> SELECT * FROM fruits;
+------+-------+-----------+
| id   | price | name      |
+------+-------+-----------+
|    1 |  1000 | 车厘子    |
|    1 |  1000 | 车厘子    |
|    1 |  1000 | 车厘子    |
|    1 |  1000 | 车厘子    |
+------+-------+-----------+
4 rows in set (0.00 sec)

四、删除数据

基本语法如下

DELETE FROM <表名> [WHERE <条件>];
mysql> SELECT * FROM fruits;
+------+-------+-----------+
| id   | price | name      |
+------+-------+-----------+
|    1 |  1000 | 车厘子    |
|    1 |  1000 | 车厘子    |
|    1 |  1000 | 车厘子    |
|    1 |  1000 | 车厘子    |
+------+-------+-----------+
4 rows in set (0.00 sec)

mysql> DELETE FROM fruits 
			 WHERE id=1;
Query OK, 4 rows affected (0.02 sec)

mysql> SELECT * FROM fruits;
Empty set (0.00 sec)

或者可以使用TRUNCATE TABLE语句,该语句是直接删除原表,再创建一张新表,所以效率更高

mysql> SELECT * FROM t1;
+------+
| n1   |
+------+
|   10 |
|   15 |
|   20 |
|   25 |
+------+
4 rows in set (0.00 sec)

mysql> TRUNCATE TABLE t1;
Query OK, 0 rows affected (0.03 sec)

mysql> SELECT * FROM t1;
Empty set (0.00 sec)

五、为表添加计算列

  • 计算列:即某列的值是根据其它列计算而来的
  • CREATE TABLE和ALTER TABLE语句均支持计算列
  • 使用GENERATED ALWAYS关键字表示计算列

基本语法如下

CREATE TABLE <表名> (
	<字段名 字段类型> GENERATED ALWAYS AS (表达式) [VIRTUAL|STORED] [约束条件]
);

例子如下

mysql> CREATE TABLE tab1 (
  		     a INT, 
  				 b INT, 
  				 c INT GENERATED ALWAYS AS (a*b) VIRTUAL);
Query OK, 0 rows affected (0.06 sec)

mysql> INSERT INTO tab1 (a, b) 
			 VALUES 
			 (2, 3);
Query OK, 1 row affected (0.02 sec)

mysql> SELECT * FROM tab1;
+------+------+------+
| a    | b    | c    |
+------+------+------+
|    2 |    3 |    6 |
+------+------+------+
1 row in set (0.00 sec)