Skip to content
Go back

MySQL基础知识

Updated:
Edit page

Forrest Gump Fake Quote

Table of contents

Open Table of contents

安装后修改密码

已能以管理员身份登录时,可用账户管理语句修改密码,而不要直接更新系统表:

ALTER USER 'root'@'localhost' IDENTIFIED BY '替换为你的新密码';

这里的账户名和主机部分要与实际账户一致。安装方式不同,首次登录可能使用临时密码或本地套接字认证;先按安装包的说明完成首次登录,再执行修改。参见 MySQL ALTER USER 文档。

MySQL连接

使用mysql -u root -p 连接,-u指定用户root,-p 密码选项,如果设置了密码需要加-p选项

连接方式一(不推荐,密码会进入命令行参数)

[root ~]#mysql -u root -proot
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 10
Server version: 5.7.34 MySQL Community Server (GPL)

Copyright (c) 2000, 2021, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql>

连接方式二

[root ~]#mysql -u root -p
Enter password:
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 11
Server version: 5.7.34 MySQL Community Server (GPL)

Copyright (c) 2000, 2021, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql>

第一种写法可能把密码留在 shell 历史或进程参数中。日常连接使用第二种,让客户端提示输入密码。

确认mysql中字符编码

mysql> status
--------------
mysql  Ver 14.14 Distrib 5.7.34, for Linux (x86_64) using  EditLine wrapper

Connection id:		8
Current database:
Current user:		root@localhost
SSL:			Not in use
Current pager:		stdout
Using outfile:		''
Using delimiter:	;
Server version:		5.7.34 MySQL Community Server (GPL)
Protocol version:	10
Connection:		Localhost via UNIX socket
Server characterset:	latin1
Db     characterset:	latin1
Client characterset:	utf8
Conn.  characterset:	utf8
UNIX socket:		/var/lib/mysql/mysql.sock
Uptime:			1 day 27 min 38 sec

Threads: 1  Questions: 17  Slow queries: 0  Opens: 113  Flush tables: 1  Open tables: 106  Queries per second avg: 0.000
--------------

这份输出中,客户端和连接字符集是 utf8,服务端和当前数据库却是 latin1,两边并不一致。可以继续用 SHOW VARIABLES LIKE 'char%'; 查看各项设置。

mysql> SHOW VARIABLES LIKE 'char%';
+--------------------------+----------------------------+
| Variable_name            | Value                      |
+--------------------------+----------------------------+
| character_set_client     | utf8                       |
| character_set_connection | utf8                       |
| character_set_database   | latin1                     |
| character_set_filesystem | binary                     |
| character_set_results    | utf8                       |
| character_set_server     | latin1                     |
| character_set_system     | utf8                       |
| character_sets_dir       | /usr/share/mysql/charsets/ |
+--------------------------+----------------------------+
8 rows in set (0.01 sec)

创建数据库

CREATE DATABASE 数据库名

mysql> create database db1;
Query OK, 1 row affected (0.00 sec)

查询数据库

SHOW DATABASES;

mysql> SHOW DATABASES;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| db1                |
+--------------------+
2 rows in set (0.00 sec)

指定数据库

mysql> use db1
Database changed

显示当前数据库

SELECT DATABASE();

mysql> SELECT DATABASE();
+------------+
| DATABASE() |
+------------+
| db1        |
+------------+
1 row in set (0.00 sec)

创建表

CREATE TABLE 表名 (列名1 数据类型1,列名2 数据类型2 ……)

mysql> CREATE TABLE tb1 (empid VARCHAR(10),name VARCHAR(10),age INT);
Query OK, 0 rows affected (0.53 sec)

显示所有的表

mysql> SHOW TABLES;
+---------------+
| Tables_in_db1 |
+---------------+
| tb1           |
+---------------+
1 row in set (0.00 sec)

指定字符编码创建表

mysql> CREATE TABLE tb2 (empid VARCHAR(10),name VARCHAR(10),age INT) CHARSET=utf8;
Query OK, 0 rows affected (0.55 sec)

字符集有服务端、数据库、表和列等层级。新建库表如果省略设置,会沿用对应的默认值,不应假定它一定是 utf8。现代 MySQL 中优先明确使用 utf8mb4,它能表示完整的 Unicode 字符,包括常见 emoji。

CREATE DATABASE practice CHARACTER SET utf8mb4;

参见 MySQL utf8mb4 字符集。

关系数据库

现在使用最为广泛的数据库是关系数据库(Relational DataBase,RDB)。 在关系型数据库中,一条数据用多少个项目来表示。例如关系型数据库将一条会员数据分成会员编号、姓名、住址和出生年月等项目,然后将各个会员的相关数据收集起来。 一条数据称为记录(record),各个项目成为列(column),在刚才的例子中xxx先生的数据是记录,会员编号和姓名等项目是列。 如果想象成Excel的工作表(work sheet),横向的一行就相当于记录。注意,纵向的一列中输入的是相同类型的数据。 收集这些记录的结构称为表(table)。一个数据库中可以包括多个表。

创建数据库

mysql> create DATABASE test;
Query OK, 1 row affected (0.02 sec)

Query OK提示成功,表示我们成功创建了数据库db1,库名和表名是否区分大小写,与文件系统和 lower_case_table_names 配置有关。跨系统迁移时可以统一使用小写命名,再核对目标实例的设置,不能只根据操作系统名称判断。

显示数据库

mysql> SHOW DATABASES;
+--------------------+
| Database           |
+--------------------+
| test                |
| information_schema |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
5 rows in set (0.00 sec)

mysql数据库是负责存储MySQL各种信息的数据库,它保存了管理用户信息的表user等。

指定数据库

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
| test               |
+--------------------+
5 rows in set (0.00 sec)

mysql> use test
Database changed
mysql>

格式:use 数据库名 在使用use选择数据库的状态下也能够操作其他数据库中的表。这时可以像“数据库名.表名”这样把数据库名和表名用“.”连接起来。例如,当从其他数据库访问数据库db2中的表table的所有记录时,可以使用下面的命令:

select * from db2.table;

显示当前使用的数据库

mysql> select database();
+------------+
| database() |
+------------+
| test       |
+------------+
1 row in set (0.00 sec)

启动时选择数据库

root@52coder:~# mysql test -u root -proot
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 11
Server version: 8.0.33-0ubuntu0.22.04.2 (Ubuntu)
Copyright (c) 2000, 2023, Oracle and/or its affiliates.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> select database();
+------------+
| database() |
+------------+
| test       |
+------------+
1 row in set (0.00 sec)

创建表 &&显示表结构

mysql> create table employ (empid VARCHAR(10),name VARCHAR(10),age INT);
Query OK, 0 rows affected (0.04 sec)

mysql> DESC employ;
+-------+-------------+------+-----+---------+-------+
| Field | Type        | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| empid | varchar(10) | YES  |     | NULL    |       |
| name  | varchar(10) | YES  |     | NULL    |       |
| age   | int         | YES  |     | NULL    |       |
+-------+-------------+------+-----+---------+-------+
3 rows in set (0.00 sec)

Null 列说明该字段是否允许 SQL 的 NULL,Default 显示默认值。省略一个字段、显式写入 NULL 和写入空字符串是三件不同的事。Field 是列名,Type 是数据类型。

显示所有的表

mysql> show tables;
+----------------+
| Tables_in_test |
+----------------+
| employ         |
+----------------+
1 row in set (0.00 sec)

mysql>

创建表指定字符编码

mysql>create table employ (empid VARCHAR(10),name VARCHAR(10),age INT) CHARSET=utf8;

插入数据

INSERT INTO 表名 VALUES(数据1,数据2);

mysql> desc employ;
+-------+-------------+------+-----+---------+-------+
| Field | Type        | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| empid | varchar(10) | YES  |     | NULL    |       |
| name  | varchar(10) | YES  |     | NULL    |       |
| age   | int         | YES  |     | NULL    |       |
+-------+-------------+------+-----+---------+-------+
3 rows in set (0.00 sec)

mysql> insert into employ values('A101','jackma',50);
Query OK, 1 row affected (0.03 sec)

VARCHAR(10) 的长度限制按字符计算。输入超长内容时,严格模式通常会报错;非严格模式下可能截断并给出警告。不要依赖静默截断来处理数据,先查看 @@sql_mode,执行后也可用 SHOW WARNINGS 检查。参见 MySQL SQL 模式。

指定列名插入记录

INSERT INTO 表名 (列名1,列名2,列名3) VALUES(数据1,数据2,数据3)

mysql> insert into employ (age,name,empid) VALUES(23,'马云','A104');
Query OK, 1 row affected (0.02 sec)

一次性输入多条数据

INSERT INTO 表名 (列名1,列名2,列名3) VALUES(数据1,数据2,数据3),(数据1,数据2,数据3),(数据1,数据2,数据3),(数据1,数据2,数据3)

mysql> insert into employ (age,name,empid) VALUES(24,'马化腾','A105'),(28,'丁磊 ','A106'),(29,'李彦宏','A107');
Query OK, 3 rows affected (0.02 sec)
Records: 3  Duplicates: 0  Warnings: 0

mysql>

显示数据

mysql> select * from employ;
+-------+-----------+------+
| empid | name      | age  |
+-------+-----------+------+
| A101  | jackma    |   50 |
| A104  | 马云      |   23 |
| A105  | 马化腾    |   24 |
| A106  | 丁磊      |   28 |
| A107  | 李彦宏    |   29 |
+-------+-----------+------+
5 rows in set (0.00 sec)

使用SELECT输出指定的值

SELECT命令还能用于显示与数据库无关的值。比如:

mysql> select '测试' ;
+--------+
| 测试   |
+--------+
| 测试   |
+--------+
1 row in set (0.00 sec)

这种方法适用于确认函数的值或计算结果。例如:

mysql> select (2+3)*4;
+---------+
| (2+3)*4 |
+---------+
|      20 |
+---------+
1 row in set (0.00 sec)

mysql>

复制表

mysql> select * from employ;
+-------+-----------+------+
| empid | name      | age  |
+-------+-----------+------+
| A101  | jackma    |   50 |
| A104  | 马云      |   23 |
| A105  | 马化腾    |   24 |
| A106  | 丁磊      |   28 |
| A107  | 李彦宏    |   29 |
+-------+-----------+------+
5 rows in set (0.00 sec)

mysql> create table employ1 select * from employ;
Query OK, 5 rows affected (0.03 sec)
Records: 5  Duplicates: 0  Warnings: 0

mysql> select * from employ1;
+-------+-----------+------+
| empid | name      | age  |
+-------+-----------+------+
| A101  | jackma    |   50 |
| A104  | 马云      |   23 |
| A105  | 马化腾    |   24 |
| A106  | 丁磊      |   28 |
| A107  | 李彦宏    |   29 |
+-------+-----------+------+
5 rows in set (0.00 sec)

CREATE TABLE table2 SELECT * FROM table1; 会按查询结果创建表并写入数据,但不会完整复制原表的索引和约束。若要先复制结构,可用 CREATE TABLE table2 LIKE table1;,再执行 INSERT INTO table2 SELECT * FROM table1;;外键等对象仍需单独核对。

修改表

修改列的数据类型

mysql> desc employ;
+-------+-------------+------+-----+---------+-------+
| Field | Type        | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| empid | varchar(10) | YES  |     | NULL    |       |
| name  | varchar(10) | YES  |     | NULL    |       |
| age   | int         | YES  |     | NULL    |       |
+-------+-------------+------+-----+---------+-------+
3 rows in set (0.01 sec)

mysql> alter table employ modify name VARCHAR(100);
Query OK, 5 rows affected (0.06 sec)
Records: 5  Duplicates: 0  Warnings: 0

mysql> desc employ;
+-------+--------------+------+-----+---------+-------+
| Field | Type         | Null | Key | Default | Extra |
+-------+--------------+------+-----+---------+-------+
| empid | varchar(10)  | YES  |     | NULL    |       |
| name  | varchar(100) | YES  |     | NULL    |       |
| age   | int          | YES  |     | NULL    |       |
+-------+--------------+------+-----+---------+-------+
3 rows in set (0.00 sec)

修改列的数据类型格式: alter table 表名 modify 列名 数据类型; 注意:数据类型的修改必须具有兼容性,不具有兼容性的修改会导致错误发生。例如把 VARCHAR(100) 缩成 VARCHAR(50),已有长数据可能使语句失败,或在特定 SQL 模式下被截断。变更前先查询超长记录,并核对实际模式。

添加列

添加列的格式: alter table 表名 add 列名 数据类型

mysql> desc employ;
+-------+--------------+------+-----+---------+-------+
| Field | Type         | Null | Key | Default | Extra |
+-------+--------------+------+-----+---------+-------+
| empid | varchar(10)  | YES  |     | NULL    |       |
| name  | varchar(100) | YES  |     | NULL    |       |
| age   | int          | YES  |     | NULL    |       |
+-------+--------------+------+-----+---------+-------+
3 rows in set (0.00 sec)

mysql> alter table employ add birth DATETIME;
Query OK, 0 rows affected (0.04 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> desc employ;
+-------+--------------+------+-----+---------+-------+
| Field | Type         | Null | Key | Default | Extra |
+-------+--------------+------+-----+---------+-------+
| empid | varchar(10)  | YES  |     | NULL    |       |
| name  | varchar(100) | YES  |     | NULL    |       |
| age   | int          | YES  |     | NULL    |       |
| birth | datetime     | YES  |     | NULL    |       |
+-------+--------------+------+-----+---------+-------+
4 rows in set (0.01 sec)

插入数据记录

mysql> desc employ;
+-------+--------------+------+-----+---------+-------+
| Field | Type         | Null | Key | Default | Extra |
+-------+--------------+------+-----+---------+-------+
| empid | varchar(10)  | YES  |     | NULL    |       |
| name  | varchar(100) | YES  |     | NULL    |       |
| age   | int          | YES  |     | NULL    |       |
+-------+--------------+------+-----+---------+-------+
3 rows in set (0.00 sec)

mysql> alter table employ add birth DATETIME;
Query OK, 0 rows affected (0.04 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> desc employ;
+-------+--------------+------+-----+---------+-------+
| Field | Type         | Null | Key | Default | Extra |
+-------+--------------+------+-----+---------+-------+
| empid | varchar(10)  | YES  |     | NULL    |       |
| name  | varchar(100) | YES  |     | NULL    |       |
| age   | int          | YES  |     | NULL    |       |
| birth | datetime     | YES  |     | NULL    |       |
+-------+--------------+------+-----+---------+-------+
4 rows in set (0.01 sec)

mysql> insert into employ VALUES('N1008','风清扬',25,'1991-08-03 22:00:00');
Query OK, 1 row affected (0.01 sec)

mysql> select * from employ;
+-------+-----------+------+---------------------+
| empid | name      | age  | birth               |
+-------+-----------+------+---------------------+
| A101  | jackma    |   50 | NULL                |
| A104  | 马云      |   23 | NULL                |
| A105  | 马化腾    |   24 | NULL                |
| A106  | 丁磊      |   28 | NULL                |
| A107  | 李彦宏    |   29 | NULL                |
| N1008 | 风清扬    |   25 | 1991-08-03 22:00:00 |
+-------+-----------+------+---------------------+
6 rows in set (0.00 sec)

由于birth是DATETIME类型,如果不输入时间,会被自动设置成“00:00:00”,即0点0分0秒。

修改列的位置

把列添加到最前面

格式: alter table 表名 add 字段 类型 first;

mysql> desc employ;
+-------+--------------+------+-----+---------+-------+
| Field | Type         | Null | Key | Default | Extra |
+-------+--------------+------+-----+---------+-------+
| empid | varchar(10)  | YES  |     | NULL    |       |
| name  | varchar(100) | YES  |     | NULL    |       |
| age   | int          | YES  |     | NULL    |       |
| birth | datetime     | YES  |     | NULL    |       |
+-------+--------------+------+-----+---------+-------+
4 rows in set (0.01 sec)

mysql> alter table employ add date DATE first;
Query OK, 0 rows affected (0.03 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> desc employ;
+-------+--------------+------+-----+---------+-------+
| Field | Type         | Null | Key | Default | Extra |
+-------+--------------+------+-----+---------+-------+
| date  | date         | YES  |     | NULL    |       |
| empid | varchar(10)  | YES  |     | NULL    |       |
| name  | varchar(100) | YES  |     | NULL    |       |
| age   | int          | YES  |     | NULL    |       |
| birth | datetime     | YES  |     | NULL    |       |
+-------+--------------+------+-----+---------+-------+
5 rows in set (0.01 sec)

把列添加到任意位置

格式: alter table 表名 add 字段 类型 after empid;

mysql> desc employ;
+-------+--------------+------+-----+---------+-------+
| Field | Type         | Null | Key | Default | Extra |
+-------+--------------+------+-----+---------+-------+
| date  | date         | YES  |     | NULL    |       |
| empid | varchar(10)  | YES  |     | NULL    |       |
| name  | varchar(100) | YES  |     | NULL    |       |
| age   | int          | YES  |     | NULL    |       |
| birth | datetime     | YES  |     | NULL    |       |
+-------+--------------+------+-----+---------+-------+
5 rows in set (0.00 sec)

mysql> alter table employ add grade int after age;
Query OK, 0 rows affected (0.03 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> desc employ;
+-------+--------------+------+-----+---------+-------+
| Field | Type         | Null | Key | Default | Extra |
+-------+--------------+------+-----+---------+-------+
| date  | date         | YES  |     | NULL    |       |
| empid | varchar(10)  | YES  |     | NULL    |       |
| name  | varchar(100) | YES  |     | NULL    |       |
| age   | int          | YES  |     | NULL    |       |
| grade | int          | YES  |     | NULL    |       |
| birth | datetime     | YES  |     | NULL    |       |
+-------+--------------+------+-----+---------+-------+
6 rows in set (0.00 sec)

修改列的顺序

mysql> desc employ;
+-------+--------------+------+-----+---------+-------+
| Field | Type         | Null | Key | Default | Extra |
+-------+--------------+------+-----+---------+-------+
| date  | date         | YES  |     | NULL    |       |
| empid | varchar(10)  | YES  |     | NULL    |       |
| name  | varchar(100) | YES  |     | NULL    |       |
| age   | int          | YES  |     | NULL    |       |
| grade | int          | YES  |     | NULL    |       |
| birth | datetime     | YES  |     | NULL    |       |
+-------+--------------+------+-----+---------+-------+
6 rows in set (0.00 sec)

mysql> alter table employ modify birth datetime first;
Query OK, 0 rows affected (0.05 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> desc employ;
+-------+--------------+------+-----+---------+-------+
| Field | Type         | Null | Key | Default | Extra |
+-------+--------------+------+-----+---------+-------+
| birth | datetime     | YES  |     | NULL    |       |
| date  | date         | YES  |     | NULL    |       |
| empid | varchar(10)  | YES  |     | NULL    |       |
| name  | varchar(100) | YES  |     | NULL    |       |
| age   | int          | YES  |     | NULL    |       |
| grade | int          | YES  |     | NULL    |       |
+-------+--------------+------+-----+---------+-------+
6 rows in set (0.00 sec)

修改列名和数据类型

alter table 表名 change 修改前的列名 修改后的列名 修改后的数据类型;

mysql> desc employ;
+-------+--------------+------+-----+---------+-------+
| Field | Type         | Null | Key | Default | Extra |
+-------+--------------+------+-----+---------+-------+
| date  | date         | YES  |     | NULL    |       |
| empid | varchar(10)  | YES  |     | NULL    |       |
| name  | varchar(100) | YES  |     | NULL    |       |
| age   | int          | YES  |     | NULL    |       |
| grade | int          | YES  |     | NULL    |       |
+-------+--------------+------+-----+---------+-------+
5 rows in set (0.00 sec)

mysql> alter table employ change date birthday datetime;
Query OK, 6 rows affected (0.05 sec)
Records: 6  Duplicates: 0  Warnings: 0

mysql> desc employ;
+----------+--------------+------+-----+---------+-------+
| Field    | Type         | Null | Key | Default | Extra |
+----------+--------------+------+-----+---------+-------+
| birthday | datetime     | YES  |     | NULL    |       |
| empid    | varchar(10)  | YES  |     | NULL    |       |
| name     | varchar(100) | YES  |     | NULL    |       |
| age      | int          | YES  |     | NULL    |       |
| grade    | int          | YES  |     | NULL    |       |
+----------+--------------+------+-----+---------+-------+
5 rows in set (0.00 sec)

删除列

alter table 表名 drop 列名;

mysql> desc employ;
+----------+--------------+------+-----+---------+-------+
| Field    | Type         | Null | Key | Default | Extra |
+----------+--------------+------+-----+---------+-------+
| datetime | date         | YES  |     | NULL    |       |
| date     | date         | YES  |     | NULL    |       |
| empid    | varchar(10)  | YES  |     | NULL    |       |
| name     | varchar(100) | YES  |     | NULL    |       |
| age      | int          | YES  |     | NULL    |       |
| grade    | int          | YES  |     | NULL    |       |
+----------+--------------+------+-----+---------+-------+
6 rows in set (0.01 sec)

mysql> alter table employ drop datetime;
Query OK, 0 rows affected (0.04 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> desc employ;
+-------+--------------+------+-----+---------+-------+
| Field | Type         | Null | Key | Default | Extra |
+-------+--------------+------+-----+---------+-------+
| date  | date         | YES  |     | NULL    |       |
| empid | varchar(10)  | YES  |     | NULL    |       |
| name  | varchar(100) | YES  |     | NULL    |       |
| age   | int          | YES  |     | NULL    |       |
| grade | int          | YES  |     | NULL    |       |
+-------+--------------+------+-----+---------+-------+
5 rows in set (0.00 sec)

主键

创建唯一记录时,会给列设置一个用于和其他列进行区分的特殊属性。 在这种情况下需要用到的就是主键(PRIMARY KEY)。主键是在多条记录中用于确定一条记录时使用的标识符。主键的特点: 没有重复的值、不允许输入空值(NULL)

创建主键

mysql> create table t_pk (a INT PRIMARY KEY,b VARCHAR(10));
Query OK, 0 rows affected (0.04 sec)

mysql> desc t_pk;
+-------+-------------+------+-----+---------+-------+
| Field | Type        | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| a     | int         | NO   | PRI | NULL    |       |
| b     | varchar(10) | YES  |     | NULL    |       |
+-------+-------------+------+-----+---------+-------+
2 rows in set (0.00 sec)

通过desc t_pk可以看到a 的key类型是PRIMARY KEY,NULL(是否为NULL)为no,不允许输入空值。

确认主键

mysql> desc t_pk;
+-------+-------------+------+-----+---------+-------+
| Field | Type        | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| a     | int         | NO   | PRI | NULL    |       |
| b     | varchar(10) | YES  |     | NULL    |       |
+-------+-------------+------+-----+---------+-------+
2 rows in set (0.00 sec)

mysql> insert into t_pk VALUES(10,'阿');
Query OK, 1 row affected (0.02 sec)

mysql> select * from t_pk;
+----+------+
| a  | b    |
+----+------+
| 10 | 阿   |
+----+------+
1 row in set (0.00 sec)

mysql> insert into t_pk(a) VALUES(10);
ERROR 1062 (23000): Duplicate entry '10' for key 't_pk.PRIMARY'

因为列a作为主键不允许输入重复的值’10’和空值NULL,所以重复时会有Duplicate entry 这样的报错。

设置唯一键

mysql> create table t_uniq1(a INT UNIQUE,b VARCHAR(10));
Query OK, 0 rows affected (0.04 sec)

mysql> desc t_uniq;
+-------+-------------+------+-----+---------+-------+
| Field | Type        | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| a     | int         | YES  | UNI | NULL    |       |
| b     | varchar(10) | YES  |     | NULL    |       |
+-------+-------------+------+-----+---------+-------+
2 rows in set (0.00 sec)

mysql> insert into t_uniq (a) VALUES(NULL);
Query OK, 1 row affected (0.02 sec)

mysql> select * from t_uniq;
+------+------+
| a    | b    |
+------+------+
| NULL | NULL |
+------+------+
1 row in set (0.00 sec)

mysql>

唯一键虽然不允许列中有重复值,但允许输入为NULL。

使列具有自动连续编号功能

要使列具有自动编号功能,就得在定义列的时候进行以下3项设置: 数据类型必须要为INT TINYINT SMALLINT等整数类型 创建表格时需要指定AUTO_INCREMENT 示例把它设为 PRIMARY KEY,保证唯一且非空;InnoDB 的自增列本身需要满足索引要求

mysql> insert into t_series(b) VALUES('子');
Query OK, 1 row affected (0.02 sec)

mysql> insert into t_series(b) VALUES('丑');
Query OK, 1 row affected (0.00 sec)

mysql> insert into t_series(b) VALUES(' 寅');
Query OK, 1 row affected (0.01 sec)

mysql> select * from t_series;
+---+------+
| a | b    |
+---+------+
| 1 | 子   |
| 2 | 丑   |
| 3 | 寅   |
+---+------+
3 rows in set (0.00 sec)

设置自增编号

自增值用于生成标识,并不保证连续无缺口。回滚、失败的插入或并发写入都可能留下空号,不能用最大编号代替记录数。

mysql> select * from t_series;
+---+------+
| a | b    |
+---+------+
| 1 | 子   |
| 2 | 丑   |
| 3 | 寅   |
+---+------+
3 rows in set (0.00 sec)

mysql> delete from t_series;
Query OK, 3 rows affected (0.02 sec)

mysql> insert into t_series(b) VALUES('武');
Query OK, 1 row affected (0.02 sec)

mysql> select * from t_series;
+---+------+
| a | b    |
+---+------+
| 4 | 武   |
+---+------+
1 row in set (0.00 sec)

mysql> insert into t_series VALUES(10,'庚');
Query OK, 1 row affected (0.02 sec)

mysql> insert into t_series(b) VALUES('耄');
Query OK, 1 row affected (0.02 sec)

mysql> select * from t_series;
+----+------+
| a  | b    |
+----+------+
|  4 | 武   |
| 10 | 庚   |
| 11 | 耄   |
+----+------+
3 rows in set (0.00 sec)

如果把表中的所有记录都删除,然后重新输入记录,编号会从之前的最大值+1开始分配。 拥有自动连续编号功能的列还可以设置指定的值(唯一),例列a中输入10,然后从11开始分配。

初始化AUTO_INCREMENT的值

mysql> alter table t_series AUTO_INCREMENT=1;
Query OK, 0 rows affected (0.03 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> select * from t_series;
+----+------+
| a  | b    |
+----+------+
|  4 | 武   |
| 10 | 庚   |
| 11 | 耄   |
+----+------+
3 rows in set (0.00 sec)

mysql> insert into t_series(b) VALUES('子');
Query OK, 1 row affected (0.02 sec)

mysql> insert into t_series(b) VALUES('丑');
Query OK, 1 row affected (0.01 sec)

mysql> select * from t_series;
+----+------+
| a  | b    |
+----+------+
|  4 | 武   |
| 10 | 庚   |
| 11 | 耄   |
| 12 | 子   |
| 13 | 丑   |
+----+------+
5 rows in set (0.00 sec)

mysql> alter table t_series AUTO_INCREMENT=100;
Query OK, 0 rows affected (0.03 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> insert into t_series(b) VALUES('正');
Query OK, 1 row affected (0.01 sec)

mysql> select * from t_series;
+-----+------+
| a   | b    |
+-----+------+
|   4 | 武   |
|  10 | 庚   |
|  11 | 耄   |
|  12 | 子   |
|  13 | 丑   |
| 100 | 正   |
+-----+------+
6 rows in set (0.00 sec)

当表中存在数据时,如果设置的编号值比已经存在的值大,也可以通过上面的语句重新设置编号的初始值。如果设置的值低于现有最大值,就不能靠它重新分配已经占用的编号。

设置列的默认值

mysql> create table tb1G (empid VARCHAR(10),name VARCHAR(10),age INT) CHARSET=utf8;
Query OK, 0 rows affected, 1 warning (0.03 sec)

mysql> desc tb1G;
+-------+-------------+------+-----+---------+-------+
| Field | Type        | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| empid | varchar(10) | YES  |     | NULL    |       |
| name  | varchar(10) | YES  |     | NULL    |       |
| age   | int         | YES  |     | NULL    |       |
+-------+-------------+------+-----+---------+-------+
3 rows in set (0.01 sec)

mysql> alter table tb1G MODIFY name VARCHAR(10) DEFAULT '未输入姓名';
Query OK, 0 rows affected (0.03 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> desc tb1G;
+-------+-------------+------+-----+-----------------+-------+
| Field | Type        | Null | Key | Default         | Extra |
+-------+-------------+------+-----+-----------------+-------+
| empid | varchar(10) | YES  |     | NULL            |       |
| name  | varchar(10) | YES  |     | 未输入姓名      |       |
| age   | int         | YES  |     | NULL            |       |
+-------+-------------+------+-----+-----------------+-------+
3 rows in set (0.00 sec)

如果插入数据时不指定name,查看name中的值。

mysql> insert into tb1G(empid,age) VALUES('64871',27);
Query OK, 1 row affected (0.02 sec)

mysql> select * from tb1G;
+-------+-----------------+------+
| empid | name            | age  |
+-------+-----------------+------+
| 64871 | 未输入姓名      |   27 |
+-------+-----------------+------+
1 row in set (0.00 sec)

创建索引

当查找表中的数据时,如果数据量过大,查找操作就会花费很多时间。如果实现在表上创建了索引,查找时就不用对全表进行扫描,而是利用索引进行扫描。

mysql> create index my_ind on tb1G(empid);
Query OK, 0 rows affected (0.05 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> show index from tb1G;
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | Visible | Expression |
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| tb1G  |          1 | my_ind   |            1 | empid       | A         |           1 |     NULL |   NULL | YES  | BTREE      |         |               | YES     | NULL       |
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
1 row in set (0.03 sec)

mysql> show index from tb1G \G
*************************** 1. row ***************************
        Table: tb1G
   Non_unique: 1
     Key_name: my_ind
 Seq_in_index: 1
  Column_name: empid
    Collation: A
  Cardinality: 1
     Sub_part: NULL
       Packed: NULL
         Null: YES
   Index_type: BTREE
      Comment:
Index_comment:
      Visible: YES
   Expression: NULL
1 row in set (0.01 sec)

mysql>

删除索引

mysql> drop index my_ind on tb1G;
Query OK, 0 rows affected (0.04 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> show index from tb1G \G
Empty set (0.00 sec)

mysql>

索引和处理速度

创建了索引并不代表一定会缩短查找时间,因为根据查找条件的不同,有时候不需要用到索引,而且在某些情况下,使用索引反而会花费更多的时间。

只有 YES/NO 两种值的列,也不能直接判定索引无用。例如一百万行里只有一百行为 NO,查询这些少量记录时,索引仍可能有帮助。是否使用索引还与数据分布、查询条件、返回行数有关,可以用 EXPLAIN SELECT ... 查看执行计划。

索引也有代价:占用空间,插入、更新、删除时需要维护。应围绕实际查询建立索引,而不是给每列都加一个。参见 MySQL 索引的使用方式。

查看已创建表的信息

mysql> show create table employ;
+--------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table  | Create Table                                                                                                                                                                                                                                                |
+--------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| employ | CREATE TABLE `employ` (
  `birthday` datetime DEFAULT NULL,
  `empid` varchar(10) DEFAULT NULL,
  `name` varchar(100) DEFAULT NULL,
  `age` int DEFAULT NULL,
  `grade` int DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci |
+--------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

mysql> show table status from test where name='employ' \G
*************************** 1. row ***************************
           Name: employ
         Engine: InnoDB
        Version: 10
     Row_format: Dynamic
           Rows: 6
 Avg_row_length: 2730
    Data_length: 16384
Max_data_length: 0
   Index_length: 0
      Data_free: 0
 Auto_increment: NULL
    Create_time: 2023-07-23 11:26:17
    Update_time: NULL
     Check_time: NULL
      Collation: utf8mb4_0900_ai_ci
       Checksum: NULL
 Create_options:
        Comment:
1 row in set (0.02 sec)

一种更简单的查询方式:
mysql> show create table employ\G
*************************** 1. row ***************************
       Table: employ
Create Table: CREATE TABLE `employ` (
  `birthday` datetime DEFAULT NULL,
  `empid` varchar(10) DEFAULT NULL,
  `name` varchar(100) DEFAULT NULL,
  `age` int DEFAULT NULL,
  `grade` int DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
1 row in set (0.00 sec)

用一个查询把前面的知识连起来

建好练习表后,可以加入几条记录,再查看默认值和 NULL 的差别:

CREATE TABLE practice.member (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(50) NOT NULL,
    email VARCHAR(255) NULL,
    active TINYINT NOT NULL DEFAULT 1
);
INSERT INTO practice.member (name, email)
VALUES ('小林', NULL), ('小周', 'zhou@example.com');
SELECT id, name FROM practice.member
WHERE email IS NULL AND active = 1
ORDER BY id;

这里省略了 id 和 active,分别交给自增机制与默认值;第一条记录的 email 则明确设为未知。查询未知值要用 IS NULL,不能写 = NULL。例子也给出了列清单,后续给表添加字段时,不容易因列的位置变化而插错数据。


Edit page
Share this post on:

Previous Post
leveldb源码阅读解析基础篇
Next Post
Ghostty + Yazi 现代终端配置指南