数据库(Database)是一种存储结构化数据的方式,一般存在两种类型的数据库: 关系型数据库、非关系型数据库。
关系型数据库: 存储二维关系表的仓库, 二维关系表是由列(特征)和行组成的。提供标准的SQL语句进行管理(创建、修改、删除)。关系型数据库一般都支持约束、索引、视图、函数、存储过程、触发器、表、字典(动态视图)等对象。【重点】
非关系型数据库: 不需要使用SQL,通过SDK(软件开发环境-模块或库, Software Development Kit)相关的方法进行操作,不支持二维关系结构,又称之为NoSQL数据库。包含redis、mongodb等。
大厂的关系型数据库: DB2(IBM公司)、Oracle(甲骨文公司)、MySQL(原Sun公司,目前也是甲骨文公司)。
其它的关系型数据库:MariDB(个人, 同MySQL一个作者)、 posgreSQL(开源的数据库)
Hadoop家族的数据库: Hive(依赖MySQL, MapReduce), Hbase(实时)
嵌入式设备中的数据库: sqlite3(没有特定的数据类型)、IotDB(分布式物联网存储的实时数据库)
限制表的设计, 让表的结构更合理、减少数据冗余。
如设计存储书相关信息的表:
ID 书编号
name 书名
cover 封面图片连接
summary 介绍
author 作者
author_years 作者的写作年限
author_nickname 作者别名
author_info 作者的介绍
author_jg 作者的家乡
author_primary_book_name 作者代表作品
store_name 书店名称
store_city 书店所在的城市
store_boss 书店的老板姓名
store_tel 书店的联系电话
publish_date 书的发布时间
publisher 出版社
假如 某一个作者有10本书,作者的相关信息重复了10次,每一条数据的作者相关信息存在近500个汉字,按UTF8编码计算,每一行作者数据的字节大小为 500*3=1500,近1.2K, 10条件记录近12K。
表的第一范式: 确保每一个列保持原子性(列不可分隔)。
根据第一范式分隔书的表为某本书的表、作者表、书店表:
-- book表
ID 书编号
name 书名
cover 封面图片连接
summary 介绍
publisher 出版社
publish_date 书的发布时间
-- 作者表
author 作者姓名
author_years 作者的写作年限
author_nickname 作者别名
author_info 作者的介绍
author_jg 作者的家乡
author_primary_book_name 作者代表作品
-- store 书店表
store_name 书店名称
store_city 书店所在的城市
store_boss 书店的老板姓名
store_tel 书店的联系电话
表的第二范式: 确保每一列的数据都和主键相关, 即表中存在主键约束。
-- 作者表
ID 作者编号(主键)
author 作者姓名
author_years 作者的写作年限
author_nickname 作者别名
author_info 作者的介绍
author_jg 作者的家乡
author_primary_book_name 作者代表作品
-- store 书店表
ID 书店(主键)
store_name 书店名称
store_city 书店所在的城市
store_addres 书店的地址
store_boss 书店的老板姓名
store_tel 书店的联系电话
表的第三范式: 确保每一列都和主键直接相关,而不能间接相关。即存在主外键关系。
-- book表
ID 书编号
name 书名
..
author_id 作者的ID, 外键
store_id 书店的ID, 外键
DDL 数据库描述或定义语言(Data Definition Language),包含数据库、表、视图、函数、索引、存储过程、触发器等对象的创建、修改和删除等操作。
创建数据库语法:
create database <数据库名> [ charset <字符集> ];
如,创建bookdb数据库
create database bookdb;
删除数据库,即将库中所有对象全部删除【慎用】
drop database [if exists] <数据库名称>;
if exists
确保SQL正常执行,如果数据库存在,则删除,不存在pass。
如,删除bookdb库
drop database bookdb;
官方文档:https://dev.mysql.com/doc/refman/8.0/en/create-table.html
创建表之前,必须先使用 use <数据库名>
语句打开某一个数据库,表示在某一数据库下创建表。
简洁的语法:
create table [if not exists] <表名>(
<字段名> <字段类型>[ (字段数据长度) ] [约束] [comment 注释文本],
...,
[constraint 表级约束语句]
) [engine=INNODB|MYISAM|MEMERY|CSV] [character set 字符集];
说明:
字段名,不能和数据库的关系冲突,一般同Python语言标识符的命名类同,由字母、数字和下划线及特殊符号组成。
字段类型,mysql提供了丰富的字段类型,包含:
字符类型char
, 固定长度的字符类型,即分配多少长度(字符的个数),即用多少长度。
【扩展】正则表达式中匹配中文的unicode编码范围: \u4e00-\u9fa5
可变字符类型varchar
,与char不同,根据内容器的多少,使用多少。不会使用给定的最大长度。
整数类型int
和integer
小数类型float
、double
、decimal
(可以设置小数点后的精确位)
日期类型 date
日期时间类型timestamp
包含日期部分和时间部分
文本类型 text
大文本类型clob
二进制类型 blob
约束, 根据不同的约束类型,检查数据,如果不合法,则抛出异常显示违反xxx
约束。
引擎
如,创建附合第三个范式的图书表、作者表
drop database if exists bookdb;
create database bookdb;
use bookdb;
drop table if exists author;
drop table if exists book;
create table if not exists author
(
author_id integer primary key auto_increment,
name varchar(20),
city varchar(20),
phone char(11)
);
create table if not exists book
(
book_id integer auto_increment comment '图书编号',
name varchar(50) unique comment '书名',
summary text comment '简介',
price decimal(5, 2) comment '单价',
act_price decimal(5, 2) comment '活动价',
cover_url varchar(100) comment '封面的URL地址',
author_id integer,
constraint book_pk primary key (book_id),
constraint book_author_fk foreign key (author_id) references author(author_id) on delete cascade
);
show tables;
【重要说明】constraint子句
constraint [约束名称] 约束类型 [index_type: {BTREE, HASH}] (字段名,...)
[references 引用表的名称(引用的字段名) on ]
约束类型: primary key、unique、foreign key
只有primary key和unique 存在index_type关键字
只有foreign key 存在 references 关键字。
准备工作:
character-set-server
是否配置default-character-set
是否配置docker run -d --name db000 -e MYSQL_ROOT_PASSWORD=root -p 3313:3306 --network db-net -v /root/mysql:/etc/mysql mysql
docker exec db000 ls /etc/mysql
docker exec -it db000 mysql -uroot -proot
mysql> show databases;
mysql> create database if not exists bookdb;
mysql> use bookdb;
mysql> source /etc/mysql/sql/init.sql
mysql> show tables;
修改表: 表名、表字段名、字段类型及字段的约束。
alter table <表名> rename [to | as] <新表名>;
修改book表为tb_book
alter table book rename as tb_book;
修改author表为tb_author
alter table author rename to tb_author;
alter table <表名> change [column] <旧列名> <新列名> <类型[(长度)]>
修改tb_book表中的name字段为book_name
alter table tb_book change column name book_name varchar(40);
修改tb_book表的price
为src_price
名称,数据类型保持不变
alter table tb_book change price src_price decimal(5,2);
alter table <表名> modify <列名> <类型[(数据长度)]> [约束]
修改tb_book表的summary
的类型改为 varchar
,且数据长度为200个字符
alter table tb_book modify summary varchar(200);
alter table <表名> drop foreign key <约束名称>;
删除tb_book表的book_author_fk
外键约束:
alter table tb_book drop foreign key book_author_fk;
依据information_schema字典库的table_constraints表
查询bookdb数据库中所有表的约束信息
select table_name,constraint_name, constraint_type
from information_schema.table_constraints
where table_schema='bookdb';
+------------+-----------------+-----------------+
| TABLE_NAME | CONSTRAINT_NAME | CONSTRAINT_TYPE |
+------------+-----------------+-----------------+
| tb_author | PRIMARY | PRIMARY KEY |
| tb_book | name | UNIQUE |
| tb_book | PRIMARY | PRIMARY KEY |
| tb_book | book_author_fk | FOREIGN KEY |
+------------+-----------------+-----------------+
alter table <表名> drop primary key;
删除tb_author表的主键约束
alter table tb_author modify author_id integer ;
alter table tb_author drop primary key;
alter table <表名> drop {
index|key} 唯一约束名或列名
【注意】默认情况唯一约束名即为列名。
删除tb_book表的name字段的唯一约束
alter table tb_book drop index name;
alter table <表名> drop [column] <字段名>;
删除tb_book的summary字段
alter table tb_book drop summary;
删除tb_book的author_id字段
alter table tb_book drop author_id;
alter table <表名>
add [column] <列名> 数据类型[(数据长度)] [约束] [comment 注释信息]
添加tb_book的summary字段,类型为text, 不能为空
alter table tb_book
add column summary text not null;
添加tb_book的author_id字段,类型为integer
alter table tb_book
add column author_id integer;
alter table <表名>
add [constraint [约束名] ]
| primary key [index_type: {using btree|hash}] (字段1, 字段2, ....)
| unique [key | index ] [index_name] [index_type] (字段1, 字段2, ...)
| foreign key (字段1, 字段2,...) references 引用表名(字段1,字段2, ...) [on delete|update restrict|cascade|set null|no action|set default]
【索引分类】主键索引、唯一索引、普通索引、组合索引
【索引类型】BTREE、HASH
添加tb_author表的author_id字段的主键约束,并设置为自增
alter table tb_author modify author_id integer primary key auto_increment;
-- alter table tb_author add primary key (author_id);
添加tb_book的author_id的外键约束,引用tb_author的author_id字段
alter table tb_book
add constraint book_author_fk foreign key (author_id) references tb_author(author_id);
drop table [if exists] <表名>
如,删除tb_book表
drop table tb_book;
【注意】无论是删除表或列,则表存在的相关约束都会被删除。
方式1:
DESC <表名>
方式2:
show create table <表名>
查看表创建时的SQL语句。
同样,查看数据库的创建SQL语句:
show create database <数据库名>
方式1: show tables
方式2: 使用information_schema字典的tables表
select table_name,table_type,table_schema
from information_schema.tables
where table_schema='bookdb';
基于SQL查询语句,快速创建一张无约束的表。
create table <表名>
select子句;
如:创建北京作者信息的表
create table tb_bejin_author
select * from tb_author where city='北京';
DML(Data Manipulation Language) 数据操纵语言,主要负责数据(行或记录)的插入、更新和删除操作。
insert语句是向表中插入一行或多行数据。
insert into <表名> [(字段1, 字段2, ...)]
values (字段值1, 字段值2, ...)
说明:
()
声明向哪些字段插入数据;默认是全部字段,插入值的顺序按创建表时声明字段顺序。()
中不同类型的数据,必须按插入值字段的类型匹配,如字符类型必须使用单引号''
,数值类型不能使用单引号,日期类型可以使用单引号。如,新增一位作者,姓名为disen,电话17791692095,城市是西安
-- author_id, name, city, phone
insert into tb_author
values(1, 'disen', '西安', '17791692095');
如,新增西安
城市的李九江
作者,他的电话是120
insert into tb_author(city, name, phone)
values('西安','李九江','120');
【注意】如果遇到自增列auto_increment
时,避免显式方式指定列值。
insert into <表名> [((字段1, 字段2, ...))] values
(字段值1, 字段值2, ...),
(字段值1, 字段值2, ...),
(字段值1, 字段值2, ...),
...
(字段值1, 字段值2, ...);
如,插入3位作者信息
insert into tb_author(city, name, phone) values
('北京', '老邓', '18918810018'),
('北京', '老刘', '17866541239'),
('杭州', '老马', '18766541908');
使用场景: 一般在分表存储数据时使用。
insert into <表名> [(字段1, ...)]
select子句;
如:将tb_author表中的所有北京的作者插入到tb_bejin_author表
insert into tb_bejin_author
select * from tb_author where city='北京';
insert into tb_book(book_name, src_price, summary, cover_url) values
('Python入门第一版本', 20, 'Python2.7精讲', null),
('Python3精通', 50, 'Disen主讲Python3.7', '/static/img/1001.jpg'),
('MySQL5.7', 90, 'Mysql 5.7的DDL,DML,DQL等', '/static/img/1002.jpg'),
('MySQL8.0', 12, 'MySQL 8.0的全部内容', null),
('Linux精通到放弃', 28, 'Linux Centos7', null),
('Linux Shell编程', 21, 'Shell脚本开发',null);
update主要负责数据的更新或修改。
update <表名> set
字段1=字段值1 [,字段2=字段值2, ...]
[where 子句]
说明: where子句,支持等值条件、逻辑运算、空值。
字段名=值
, 字段名 >= | < | <= | != 值
, 字段名 between 起始值 and 结束值
闭区间and
、or
、not
, 另外,字段名 in(值1, 值2, 值3,...)
等价于字段名=值1 or 字段名=值2 or 字段名=值3
。is null
、not null
如,更新tb_author西安的disen作者的城市为上海
update tb_author set
city='上海'
where city='西安' and name='disen';
如, 修改tb_author表中disen作者的姓名为’老狄’,城市修改为’北京’
update tb_author set
city='北京',name='老狄'
where name='disen';
如,修改tb_book表,将原价的20到30之间的所有图书打7折
select book_name, src_price,act_price
from tb_book;
-- tb_book(book_id, book_name, src_price, act_price, ....)
update tb_book set
act_price=src_price*0.7
where src_price between 20 and 30;
【注意】在更新某一字值时,可以引用原字段的数据。如act_price=src_price*0.7
。
如,将tb_book表中所有cover_url字段为空修改为/static/img/default.jpg
select book_name, cover_url from tb_book;
update tb_book set
cover_url='/static/img/default.jpg'
where cover_url is null;
【注意】更新数据时,避免全部数据更新,即必须带有where条件
delete删除表的数据,不会影响表结构本身。
delete from <表名>
[where 子句]
【注意】如果delete语句不存在where子句时,表示清空表的内容。
如, 删除tb_book表中活动价格低于10元的数据
select book_name, act_price from tb_book;
begin;
delete from tb_book
where act_price <= 15;
commit;
【练习-外键约束的数据插入和级联操作】
-- tb_author(author_id, name, city, phone)
-- tb_book(book_id, book_name, ..., author_id)
insert into tb_author(name, city, phone)
values
('老李','西安', '19887726619'),
('小王','北京', '19826661190');
mysql> select * from tb_author;
+-----------+--------+--------+-------------+
| author_id | name | city | phone |
+-----------+--------+--------+-------------+
| 1 | 老李 | 西安 | 19887726619 |
| 2 | 小王 | 北京 | 19826661190 |
+-----------+--------+--------+-------------+
2 rows in set (0.00 sec)
mysql> select book_id,book_name, author_id from tb_book;
+---------+----------------------+-----------+
| book_id | book_name | author_id |
+---------+----------------------+-----------+
| 2 | Python3精通 | NULL |
| 3 | MySQL5.7 | NULL |
| 4 | MySQL8.0 | NULL |
| 5 | Linux精通到放弃 | NULL |
+---------+----------------------+-----------+
-- 修改tb_book表的book_id是2的author_id为3,是否可以成功呢?如果不成功,抛出什么错误呢?
-- 原因: 更改的author_id不在tb_author表的主键中。
update tb_book
set author_id=3
where book_id=2;
mysql> update tb_book
-> set author_id=3
-> where book_id=2;
ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`bookdb`.`tb_book`, CONSTRAINT `book_author_fk` FOREIGN KEY (`author_id`) REFERENCES `tb_author` (`author_id`) ON DELETE CASCADE)
-- 将所有书的作者全部修改为author_id为1的作者
update tb_book
set author_id=1;
-- 删除author_id为1的作者记录
-- 外键约束的级联操作: ON DELETE CASCADE 级联删除
delete from tb_author where author_id=1;
【注意】当事务开启后,且执行了多个DML语句,在未提交事务之前,如果发生了DDL语句,则会自动提交事务。
alter table tb_book
drop foreign key book_author_fk;
-- 添加tb_book和tb_author的外键约束,支持级联删除和级联更新
alter table tb_book
add constraint book_author_fk foreign key (author_id)
references tb_author(author_id) on delete cascade on update cascade;
-- ON UPDATE CASCADE 级联更新
-- 修改author_id为1的作者编号为110: 如果外键约束中存在级联更新,则直接修改外键字段的值。
update tb_author
set author_id=110
where author_id=1;
-- 外键约束:级联删除置空
alter table tb_book
drop foreign key book_author_fk;
alter table tb_book
add constraint book_author_fk foreign key (author_id)
references tb_author(author_id) on delete set null;
begin;
delete from tb_author where author_id=110;
select book_name, author_id from tb_book;
rollback;
DQL(Data Query Language)数据查询语言,主要负责数据的查询,包含单表查询、多表查询、子查询、分组查询、条件查询、模糊查询、分页查询、窗口函数统计等。
官方文档:https://dev.mysql.com/doc/refman/8.0/en/select.html
select [distict] 字段名|表达式 [ [AS] 别名] [, 字段|表达式,...]
[ from <表名>|
在select子句中,可以选择表中的字段,也可以使用表达式(算术、函数、 关系、逻辑)。
如,查看当前时间(current_date、now())
select current_date;
select now();
mysql> select now();
+---------------------+
| now() |
+---------------------+
| 2021-09-03 06:09:03 |
+---------------------+
mysql> select now() 'this time';
+---------------------+
| this time |
+---------------------+
| 2021-09-03 06:09:03 |
+---------------------+
mysql> select current_date as cdate;
+------------+
| cdate |
+------------+
| 2021-09-03 |
+------------+
mysql> select 100>20 as ret;
+-----+
| ret |
+-----+
| 1 |
+-----+
1 row in set (0.00 sec)
mysql> select 100<20 as ret;
+-----+
| ret |
+-----+
| 0 |
+-----+
1 row in set (0.00 sec)
mysql> select 1 and 2 or 0 a123;
+------+
| a123 |
+------+
| 1 |
+------+
mysql> select uuid();
+--------------------------------------+
| uuid() |
+--------------------------------------+
| 8f232ae9-0c80-11ec-96d6-0242ac110002 |
+--------------------------------------+
mysql> select replace(uuid(), '-', '') as USERID;
+----------------------------------+
| USERID |
+----------------------------------+
| bca7edc00c8011ec96d60242ac110002 |
+----------------------------------+
create table A(year int, month int, amount float);
insert into A values
(1991, 1, 1.1),
(1991,2, 1.2),
(1992,1, 2.1),
(1992,2, 2.2);
问题存在一张A表,内容如下:
+------+-------+--------+
| year | month | amount |
+------+-------+--------+
| 1991 | 1 | 1.1 |
| 1991 | 2 | 1.2 |
| 1992 | 1 | 2.1 |
| 1992 | 2 | 2.2 |
+------+-------+--------+
请写出如下结果的SQL语句:
+------+-------+--------+
| year | m1 | m2 |
+------+-------+--------+
| 1991 | 1.1 | 1.2 |
| 1992 | 2.1 | 2.2 |
最有效的写法-SQL:
select year,
round(max(if(month=1,amount,0.0)),1) as m1,
round(max(if(month=2, amount,0.0)),1) as m2
from A
group by year;
from 关键字后面可以跟表名或子查询,如果是子查询时,必须提供别名,作为子查询结果的临时表名。 表名的别名,可以在select子句中使用。
from 后跟多个表时,需要用逗号分隔。 如果从多个表中查询数据,必须提供多个表之间的连接条件,否则会出现
笛卡尔集
。
select b.book_name, b.author_id, a.name as author_name
from tb_book b, tb_author a
where b.author_id = a.author_id;
where子句主要的作用是限制数据的范围,在select 的where子句中的字段,一般都是index索引字段(加速查询)。
where 子句中支持非常丰富的条件表达式,包含between-and、like、函数表达式、in、is null、not null等。
-- 查看活动价格在10-20之间的所有书的信息
select book_id,book_name,act_price
from tb_book
where act_price between 10 and 20;
-- 查看姓名中带`李`的作者
select * from tb_author
where name like '%李%';
【like说明】like是一种模糊匹配的查询条件,可以使用%
和_
通配符。
-- 查看姓名中第三个字符为`丽`的作者
select * from tb_author
where name like '__丽%';
-- 查看书编号为1或3或5的书信息
select * from tb_book
where book_id in (1, 3, 5);
-- 查看除作者编号为1和5之外的所有作者信息
select * from tb_author
where author_id not in (1, 5);
join语句支持多个表之间的连接,通过on指定表连接的条件。
使用join可以减少where等值连接的子句。
内连接即表示两个表都具有的数据
mysql> update tb_book set author_id=null where book_id=4;
Query OK, 1 row affected (0.02 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> select book_id,book_name, author_id from tb_book;
+---------+---------------+-----------+
| book_id | book_name | author_id |
+---------+---------------+-----------+
| 2 | Python3精通 | 110 |
| 3 | MySQL5.7 | 110 |
| 4 | MySQL8.0 | NULL |
+---------+---------------+-----------+
mysql> select author_id,name from tb_author;
+-----------+--------+
| author_id | name |
+-----------+--------+
| 2 | 小王 |