引入

上篇文章中我们简单介绍了数据库以及 MySQL 的介绍及安装,本篇文章我们主要要介绍一下 MySQL 的相关规则和语法。

使用 MySQL

连接DBMS

​ MySQL与所有客户机-服务器DBMS一样,要求执行命令之前登录到DBMS。MySQL在内部保存自己的用户列表,并且把每个用户与各种权限关联起来。

​ 在上篇文章安装MySQL过程中,我们的账号为root,密码为123456。在自己本地使用时,可以这样简单设置一下。但是在现实生产或者工作时,管理登录受到密切保护(因为对它的访问授予了创建表、删除整个数据库、更改登录和口令等完全的操作)。

在连接MySQL时,需要以下信息:

  • 主机名(计算机名)——如果连接到本地MySQL服务器,为Localhost;
  • 端口(如果使用默认端口3306之外的端口);
  • 一个合法的用户名;
  • 用户口令(也就是密码)。

例如在SQLyog中登录:

image-20211013105422565

选择数据库

​ 在你最初连接到MySQL时,没有数据库打开供你使用。在你能执行任何数据库操作之前,需要选择一个数据库。为此,我们可以使用USE关键字。

1
2
USE 表名
# 将当前数据库转到目的数据库,一般的mysql可视化程序都会输入一句“Database changed”

​ 记住,要先使用USE打开指定数据库,才能读取其中的数据并操作。

小Tip:在Windows系统上MySQL关键字一般不区分大小写(linux上就会区分,Windows上可以设置区分),所以上述例子中使用USE和use甚至是其他的组合都可以,不过MySQL语句规范:

1: 关键字与函数名称全部大写;

2: 数据库名称,表名称,字段名称全部小写;

所以在给数据库或者表等起名时,推荐使用下划线划分的形式,例如 person_table 。

了解数据库和表

​ 在建立数据库之后或者打开一个别人创建的数据库时,而且我们不知道或者忘记可以使用的数据库名怎么办?

​ 数据库、表、列、用户、权限等的信息被存储在数据库和表中。不过,内部的表一般不直接访问。可用的MySQL的SHOW命令来显示这些信息(由MySQL来负责将这些信息提取出来)。

1
2
3
4
5
6
7
8
9
10
mysql> SHOW DATABASES;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| school |
+--------------------+
4 rows in set (0.00 sec)

​ 上面展示的就是SHOW DATABASES命令的效果,返回可用数据库的一个列表。需要注意的是,MySQL用;来标志着一条命令的结束,当读者在运行sql语句没反应时,不妨检查下是不是缺少;的原因。

1
2
3
4
5
6
7
8
9
10
mysql> USE SCHOOL;                                                                  
Database changed
mysql> SHOW TABLES;
+------------------+
| Tables_in_school |
+------------------+
| normaluser |
| student |
+------------------+
2 rows in set (0.00 sec)

​ 上面展示的就是SHOW TABLES命令的效果,返回可用数据库的一个列表。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
mysql> SHOW COLUMNS FROM student;                                                   
+----------+-----------------+------+-----+--------------+-------+
| Field | Type | Null | Key | Default | Extra |
+----------+-----------------+------+-----+--------------+-------+
| Sno | int(11) | NO | PRI | NULL | |
| pwd | varchar(20) | NO | | NULL | |
| Sname | varchar(30) | NO | | NULL | |
| sex | char(2) | NO | || |
| grade | int(4) unsigned | YES | | NULL | |
| phone | varchar(50) | YES | | NULL | |
| address | varchar(255) | YES | | 地址不详 | |
| birthday | datetime | YES | | NULL | |
| email | varchar(50) | YES | | NULL | |
| idCard | varchar(18) | YES | UNI | NULL | |
+----------+-----------------+------+-----+--------------+-------+
10 rows in set (0.00 sec)

SHOW COLUMNS要求给出一个表名(例如上面的FROM student),它对每个字段返回一行,行中包含字段名、数据类型、是否允许NULL、键信息、默认值以及其他信息(例如当字段自增时在Extra一栏会显示auto_increment)。

什么是 auto_increment ? auto_increment 也就是自动增量,某些表的列需要唯一值,例如,订单编号、雇员ID等。在每个行添加到表中时,MySQL可以自动地为每个行分配下一个可用编号,不用在添加一行时手动分配唯一值(这样做必须记住最后一次使用的值)。这个功能就是所谓的自动增量。如果需要它,则必须要在用CREATE语句创建表时把它作为表定义的组成部分,我们在后面会再提到。

小Tip:上述的 SHOW COLUMNS FROM student 可以替换成 DESCRIBE student;简而言之,DESCRIBE 是 SHOW COLUMNS FROM 的一种简写,其实还可以写成 DESC(偷懒Plus)。

其他所支持的SHOW命令还有:

  • SHOW STATUS,用于显示广泛的服务器状态信息;
  • SHOW CREATE DATABASE 和 SHOW CREATE TABLE,分别用来显示创建特定数据库或表的MySQL语句;
  • SHOW GRANTS,用来显示授予用户(所有用户或特定用户)的安全权限;
  • SHOW ERRORS 和 SHOW WARNINGS,用来显示服务器错误或警告信息。

检索数据

检索列

1
2
3
4
5
6
7
8
mysql> SELECT * FROM normaluser;                                                    
+----+--------------+---------------+-------+
| id | user_account | user_password | money |
+----+--------------+---------------+-------+
| 1 | zhangsan | 123456 | 200 |
| 2 | lisi | 123456 | 250 |
+----+--------------+---------------+-------+
2 rows in set (0.00 sec)

​ 上述语句利用SELECT语句从normaluser表中检索出了所有列(*指代所有字段),等同于 SELECT user_account, user_password, money FROM normaluser。所需的的列名在SELECT关键字之后给出,FROM关键字指出从其中检索数据的表名。

小Tip:在SQLyog中操作时,可以通过操作图形化界面的方式创建数据库、表以及添加数据,可以参考这篇博文:SQLyog使用教程。命令行创建的方式之后才会讲解。

检索不同行

当我们想知道用户的常用密码是什么时,我们可以对密码进行查询:

1
2
3
4
5
6
7
8
9
mysql> SELECT user_password FROM normaluser;                                        
+---------------+
| user_password |
+---------------+
| 123456 |
| 123456 |
| 654321 |
+---------------+
3 rows in set (0.00 sec)

​ 这时候我们发现出现了重复的数据,当我们不想结果出现重复数据时,我们可以使用DISTINCT关键字,顾名思义,这个关键字将结果进行筛选,最后只剩下结果不同的列表,例如下面的效果:

1
2
3
4
5
6
7
8
mysql> SELECT DISTINCT user_password FROM normaluser;                              
+---------------+
| user_password |
+---------------+
| 123456 |
| 654321 |
+---------------+
2 rows in set (0.00 sec)

小Tip:不能部分使用DISTINCT,DISTINCT会作用于目标的所有列而不仅是前置他的列。比如给出 SELECT DISTINCT user_account, user_password FROM normaluser 时,就要求除非账号和密码都相同,否则就会被检索出来。

限制结果

SELECT语句返回所有匹配的行,它们可能是指定表中的所有行。为了返回指定条数的数据,可以使用LIMIT关键字。例子如下:

1
2
3
4
5
6
7
8
9
mysql> SELECT * FROM normaluser LIMIT 3;                                            
+----+--------------+---------------+-------+
| id | user_account | user_password | money |
+----+--------------+---------------+-------+
| 1 | zhangsan | 123456 | 200 |
| 2 | lisi | 123456 | 250 |
| 3 | wangwu | 654321 | 250 |
+----+--------------+---------------+-------+
3 rows in set (0.00 sec)

​ 上述语句使用SELECT语句检索了所有列。LIMIT 3指示MySQL返回不多于3行。当我们想知道某一行开始的后三行时,我们可以指定要检索的开始行和行数,如下所示:

1
2
3
4
5
6
7
8
9
mysql> SELECT * FROM normaluser LIMIT 2, 3;                                         
+----+--------------+---------------+-------+
| id | user_account | user_password | money |
+----+--------------+---------------+-------+
| 3 | wangwu | 654321 | 250 |
| 4 | zhangsi | 654321 | 200 |
| 5 | liwu | 789012 | 300 |
+----+--------------+---------------+-------+
3 rows in set (0.00 sec)

LIMIT 2, 3表示返回第二行以及后面的两行,也就是从第二行开始到第四行。第一个数表示开始位置,第二个数表示要返回的行数。

行 0 可能有读者奇怪上述例子中为什么第三行数据却是第二行,因为数据表中的第一行是行0而不是行1。因此,LIMIT 1, 1检索出来的是第二行数据而不是第一行数据。

当行数不够时 LIMIT中指定要检索出的数据为检索的最大行数。如果没有足够的行时,MySQL将只会返回他能返回的那么多行。

MySQL 5 中的 LIMIT 语法 从MySQL 5 开始出现一种LIMIT的另一种替代语法。LIMIT 4 OFFSET 3 意思是从行3开始取四行,就像LIMIT 3, 4 一样。

使用完全限定的表名

​ 到目前为止的例子中,我们只使用了列名来引用列。在某些情况下,我们也可以使用全限定的名字来引用列(同时使用表名和列名)。例如:

1
2
3
4
5
6
7
8
9
10
11
12
mysql> SELECT normaluser.user_password FROM school.normaluser;                      
+---------------+
| user_password |
+---------------+
| 123456 |
| 123456 |
| 654321 |
| 654321 |
| 789012 |
| 789012 |
+---------------+
6 rows in set (0.00 sec)

​ 在这条语句中,我们将user_password限定为normaluser表中的user_password字段,normaluser限定为school数据库中的normaluser表,等价于SELECT user_password FROM normaluser,在之后某些场景需要使用完全限定名。现在需要注意一下这个语法,以便到时候知道它的作用。

排序检索数据

排序数据

​ 在上面许多的操作时,我们可以看出检索的数据并没有什么严格的顺序。其实,检索出的数据并不是以纯粹的随机顺序显示的。如果不排序,数据一般将以它在底层表中出现的顺序显示。这可以是数据最初添加到表中的数据顺序。但是,如果数据后来进行过更新或者删除操作时,则此时将会受到MySQL重用回收存储空间的影响。因此,如果不明确控制的话,不能(也不应该)依赖排序顺序。在关系数据库设计理论中认为,如果不明确规定排序顺序,则不应该假定检索出的数据的顺序有意义。

子句 SQL语句由子句构成,有些子句是必需的,而有些是可选的。一个子句通常由一个关键字和所提供的数据组成。子句的例子有SELECT语句的FROM子句,我们在之前的例子中看到了这个子句的作用。

​ 当我们需要明确使用排序用SELECT语句检索出的数据,可以使用ORDER BY子句。OEDER BY子句取一个或者多个列的名字,据此对输出进行排序。例如:

1
2
3
4
5
6
7
8
9
10
11
12
mysql> SELECT user_account FROM normaluser ORDER BY user_account;                   
+--------------+
| user_account |
+--------------+
| lisi |
| liwu |
| wangliu |
| wangwu |
| zhangsan |
| zhangsi |
+--------------+
6 rows in set (0.02 sec)

​ 可以看到上述操作将用户账号以字母顺序排序(默认是升序的)展示了表中的数据,如果想要降序输出,加上DESC关键字即可。例如:

1
2
3
4
5
6
7
8
9
10
11
12
mysql> SELECT user_account FROM normaluser ORDER BY user_account DESC;              
+--------------+
| user_account |
+--------------+
| zhangsi |
| zhangsan |
| wangwu |
| wangliu |
| liwu |
| lisi |
+--------------+
6 rows in set (0.00 sec)

按多个列进行排序

​ 在实际使用时,经常需要不止一个列进行数据排序,因为可能有些数据是相等的,所以就需要多个列进行排序。为了按多个列排序,只要指定列名,列名之间用逗号分开即可(就像选择多个列时所做的那样),例如:

1
2
3
4
5
6
7
8
9
10
11
12
mysql> SELECT user_account, money FROM normaluser ORDER BY money DESC, user_account;
+--------------+-------+
| user_account | money |
+--------------+-------+
| liwu | 300 |
| lisi | 250 |
| wangliu | 250 |
| wangwu | 250 |
| zhangsan | 200 |
| zhangsi | 200 |
+--------------+-------+
6 rows in set (0.00 sec)

​ 上述例子中,我们将用户按照余额进行了降序排序,当所持金额相同时按照名字升序排列。这就是实现了对排序规则的排序。

在每个列上降序排序 如果想在多个列上进行降序排序,必须对每个列指定DESC关键字。

小Tip:有细心的读者可能发现了,在前面还出现过一次DESC关键字

DESC table_name;

PS:此处desc是describe的缩写,用法: desc 表名/查询语句

SELECT user_account FROM normaluser ORDER BY user_account DESC;

PS:此处desc是descend的缩写, 用法:select * from 表 order by 字段 desc

ORDER BY子句的位置 在给出ORDER BY子句时,应该保证它位于FROM子句之后。如果使用LIMIT,它必须位于ORDER BY之后。使用子句的次序不当讲产生错误消息。关于子句的顺序,后面我们应该还会提到。

过滤数据

使用 WHERE 子句

​ 数据库表中通常包含大量的数据,很少需要检索表中所有行。通常只会根据特定操作或报告的需要提取表数据的子集。只检索所需数据需要指定搜索条件(也叫过滤条件)。

​ 在SELECT语句中,数据根据WHERE子句中指定的搜索条件进行过滤。WHERE子句在表名(FROM子句)之后给出,例如:

1
2
3
4
5
6
7
8
9
mysql> SELECT * FROM normaluser WHERE money = 250;                                  
+----+--------------+---------------+-------+
| id | user_account | user_password | money |
+----+--------------+---------------+-------+
| 2 | lisi | 123456 | 250 |
| 3 | wangwu | 654321 | 250 |
| 6 | wangliu | 789012 | 250 |
+----+--------------+---------------+-------+
3 rows in set (0.02 sec)

​ 上面展示了一个简单的筛选:它检查一个列是否有指定的值,据此进行筛选。但是SQL支持的不仅仅是这样的简单筛选。

WHERE 子句的位置 在同时使用ORDER BY位于WHERE之后,否则将会产生错误。

WHERE 子句操作符

操作数 说明
= 等于
<> 不等于
!= 不等于
< 小于
<= 小于等于
> 大于
>= 大于等于
BETWEEN 在指定两个数之间

不匹配检查

​ 在上面的例子中,我们已经举例了匹配单个值得情况,以下例子例出所持金额不是250的用户:

1
2
3
4
5
6
7
8
9
mysql> SELECT * FROM normaluser WHERE money <> 250;                                 
+----+--------------+---------------+-------+
| id | user_account | user_password | money |
+----+--------------+---------------+-------+
| 1 | zhangsan | 123456 | 200 |
| 4 | zhangsi | 654321 | 200 |
| 5 | liwu | 789012 | 300 |
+----+--------------+---------------+-------+
3 rows in set (0.01 sec)

何时使用引号 如果仔细观察许多 WHERE 子句中使用的条件,不难发现有些值被括在单引号内,而有些值未被括起来。单引号用来限定字符串。如果将值与串类型的列进行比较,则需要限定引号。用来与数值列进行比较的值不用引号。

​ 上面的例子同样可以使用 != 而不是 <> 操作符;

范围值查询

​ 为了检查某个范围的值,可以使用 BETWEEN 操作符。其语法与其他 WHERE 子句的操作符稍有不同,因为它需要两个值,即范围的开始值和结束值。例如以下的例子,我们检索了所持金额在250到300的所有用户:

1
2
3
4
5
6
7
8
9
10
mysql> SELECT * FROM normaluser WHERE money between 250 and 300;                    
+----+--------------+---------------+-------+
| id | user_account | user_password | money |
+----+--------------+---------------+-------+
| 2 | lisi | 123456 | 250 |
| 3 | wangwu | 654321 | 250 |
| 5 | liwu | 789012 | 300 |
| 6 | wangliu | 789012 | 250 |
+----+--------------+---------------+-------+
4 rows in set (0.00 sec)

空值检查

​ 在创建表时,表设计人员可以指定其中的列是否可以不包含值。在一个列不包含值时,称其为包含空值NULL。

NULL 无值(no value),它与字段包含0、空字符串或仅仅包含空格不同。实际上,它们各不相同。

​ SELECT语句有一个特殊的 WHERE 子句,用来检查具有 NULL 值的列。这个 WHERE 子句就是 IS NULL 子句。其语法如下:

1
2
mysql> select * from normaluser where user_account  is null;             
Empty set (0.00 sec)

​ 这条语句返回了所有没有设置账号的用户的用户信息,由于表中没有这样的数据,所以没有返回数据。但是假如在数据录入没有录入数据而且表结构允许此字段出现空值时,则此列将包含 NULL 值。

NULL 与不匹配 在通过过滤出不具有特定值的行时,你可能希望返回具有 NULL 的行。但是,不行。因为未知具有特殊的含义,数据库不知道它们是否匹配,所以在匹配或不匹配过滤时不返回它们。

因此,在过滤数据时,一定要验证返回数据中确实给出了被过滤列具有 NULL 的行。

感谢

本文参考《MySQL必知必会》