SQL(Structured Query Language)结构化查询语⾔,用于存取、查询、更新数据以及管理关系型数据库系统
SQL是在1981年由IBM公司推出,⼀经推出基于其简洁的语法在数据库中得到了广泛的应用,成为主流数据库的通用规范。
根据SQL指令完成的数据库操作的不同,可以将SQL指令分为四类
DDL(Data Definition Language)
数据定义语⾔DML(Data Manipulation Language)
数据操作/操纵语⾔DQL(Data Query Language)
数据查询语⾔DCL(Data Control Language)
数据控制语⾔在MySQL Command Line Client 或者Navicat等工具中都可以编写SQL指令
;
结束空格
进行分隔使⽤DDL语句可以创建数据库、查询数据库、修改数据库、删除数据库
## 查询数据库
# 显示当前mysql中的数据库列表
show databases;
# 显示指定名称的数据的创建的SQL指令
show create database <dbName>;
## 创建数据库
# 创建数据库 dbName表示创建的数据库名称,可以⾃定义
create database <dbName>;
# 创建数据库,当指定名称的数据库不存在时执行创建
create database if not exists <dbName>;
# 在创建数据库的同时指定数据库的字符集(字符集:数据存储在数据库中采⽤的编码格式utf8 gbk)
create database <dbName> character set utf8;
## 修改数据库 修改数据库字符集
alter database <dbName> character set utf8; # utf8 gbk
## 删除数据库 删除数据库时会删除当前数据库中所有的数据表以及数据表中的数据
# 删除数据库
drop database <dbName>;
# 如果数据库存在则删除数据库
drop database if exists <dbName>;
## 使⽤/切换数据库
use <dbName>
数据表实际就是⼀个⼆维的表格,⼀个表格是由多列组成,表格中的每⼀类称之为表格的⼀个字段。
## 创建数据表
create table user(
id int not null unique,
name varchar(20) not null,
gender char(2) not null,
age int not null,
tel char(11) not null unique,
address varchar(30) unique
);
## 查询数据表
show tables;
## 查询表结构
desc <tableName>;
## 删除数据表
drop table <tableName>;
## 当数据表存在时删除数据表
drop table if exists <tableName>;
## 修改数据表
# 修改表名
alter table <tableName> rename to <newTableName>;
# 数据表也是有字符集的,默认字符集和数据库⼀致
alter table <tableName> character set utf8;
# 添加列(字段)
alter table <tableName> add <columnName> varchar(200);
# 修改列(字段)的列表和类型
alter table <tableName> change <oldColumnName> <newCloumnName> <type>;
# 只修改列(字段)类型
alter table <tableName> modify <columnName> <newType>;
# 删除列(字段)
alter table <tableName> drop <columnName>;
数据类型,指的是数据表中的列中⽀持存放的数据的类型
在mysql中有多种数据类型可以存放数值,不同的类型存放的数值的范围或者形式是不同的
类型 | 内存空间大小 | 范围 | 说明 |
---|---|---|---|
tinyint | 1byte | 有符号 -128~127 ⽆符号 0~255 |
特小型整数(年龄) |
smallint | 2byte | 有符号 -32768 ~ 32767 ⽆符号 0~65535 |
小型整数 |
mediumint | 3byte | 有符号 -2^31 ~ 2^31 - 1 ⽆符号 0~2^32-1 |
中型整数 |
int/integer | 4byte | 整数 | |
bigint | 8byte | 大型整数 | |
float | 4byte | 单精度 | |
double | 8byte | 双精度 | |
decimal | 第⼀参数+2 | decimal(10,2) 表示数值⼀共有10位 ⼩数位有2位 |
存储字符序列的类型
类型 | 字符长度 | 说明 |
---|---|---|
char | 0~255字节 | 定⻓字符串,最多可以存储255个字符 ;当我们指定数据表字段为char(n) 此列中的数据最⻓为n个字符,如果添加的数据少于n,则补’\u0000’⾄n⻓度 |
varchar | 0~65536字节 | 可变⻓度字符串,此类型的类最⼤⻓度为65535 |
tinyblob | 0~255 字节 | 存储⼆进制字符串 |
blob | 0~65535 | 存储⼆进制字符串 |
mediumblob | 0~1677215字节 | 存储⼆进制字符串 |
longblob | 0~4294967295字节 | 存储⼆进制字符串 |
tinytext | 0~255字节 | ⽂本数据(字符串) |
text | 0~65535字节 | ⽂本数据(字符串) |
mediumtext | 0~1677215字节 | ⽂本数据(字符串) |
longtext | 0~4294967295字节 | ⽂本数据(字符串) |
在MySQL数据库中,我们可以使用字符串来存储时间,但是如果我们需要基于时间字段进行查询操作(查询在某个时间段内的数据)就不便于查询实现
类型 | 格式 | 说明 |
---|---|---|
date | 2021-09-13 | 日期,只存储年月日 |
time | 11:12:13 | 时间,只存储时分秒 |
year | 2021 | 年份 |
datetime | 2021-09-13 11:12:13 | 日期+时间,存储年⽉日时分秒 |
timestamp | 20210913 111213 | 日期+时间 (时间戳) |
在创建数据表的时候,指定的对数据表的列的数据限制性的要求(对表的列中的数据进行限制)
为什么要给表中的列添加约束呢?
字段常见的约束有哪些呢?
限制数据表中此列的值必须提供
创建表:设置图书表的 name not null
create table books(
id int,
name varchar(10) not null,
author varchar(20)
);
添加数据:id和author 不给值,可以默认为null,如果name不给值则提示添加错误
如果添加中文报错,在创建数据库时选择编码为utf8或utf8mb4
在表中的多条数据,此列的值不能重复
创建表:设置图书表的name为 unique
create table books(
id int unique,
name varchar(10) not null,
author varchar(20)
);
主键——就是数据表中记录的唯⼀标识,在⼀张表中只能有⼀个主键(主键可以是⼀个列,也可以是多个列的组合)
当⼀个字段声明为主键之后,添加数据时:
## 方式一:创建表时添加主键约束
create table books(
id int primary key,
name varchar(10) not null,
author varchar(20)
);
## 方式二:创建表时添加主键约束
create table books(
id int ,
name varchar(10) not null,
author varchar(20),
primary key(id)
);
## 删除数据表主键约束
alter table books drop primary key;
## 创建表时没有添加主键约束
create table books(
id int ,
name varchar(10) not null,
author varchar(20)
);
## 创建表之后添加主键约束
alter table books modify id int primary key;
在我们创建⼀张数据表时,如果数据表中有列可以作为主键(例如:用户表的id、图书表的id)我们可以直接这是这个列为主键;
当有些数据表中没有合适的列作为主键时,我们可以额外定义⼀个与记录本身⽆关的列(ID)作为主键,此列数据⽆具体的含义主要⽤于标识⼀条记录,在mysql中我们可以将此列定义为int,同时设置为自动增长
,当我们向数据表中新增⼀条记录时,⽆需提供ID列的值,它会⾃动⽣成。
## 定义主键⾃动增⻓
## 定义int类型字段⾃动增⻓: auto_increment
create table types(
type_id int primary key auto_increment,
type_name varchar(20) not null,
type_remark varchar(100)
);
注意:⾃动增⻓从1开始,每添加⼀条记录,⾃动的增⻓的列会⾃定+1,当我们把某条记录删除之后再添加数据,⾃动增⻓的数据也不会重复⽣成(⾃动增⻓只保证唯⼀性、不保证连续性)
联合主键——将数据表中的多列组合在⼀起设置为表的主键
## 定义联合主键
create table grades(
user_id int,
course_id int,
score int,
primary key(user_id, course_id)
);
注意:在实际企业项⽬的数据库设计中,联合主键使⽤频率并不⾼;当⼀个张数据表中没有明确的字段可以作为主键时,我们可以额外添加⼀个ID字段作为主键。
用于完成对数据表中数据的插入、删除、修改操作
## 插入数据
insert into <tableName>(columnName,columnName....)
values(value1,value2....);
## 删除数据--从数据表中删除满⾜特定条件(所有)的记录
delete from <tableName> [where conditions];
## 删除数据--一次性地从表中删除所有的数据并不把单独的删除操作记录记入日志保存,删除行是不能恢复的。
## 并且在删除的过程中不会激活与表有关的删除触发器。执行速度快。
truncate table user;
### 修改数据--对数据表中已经添加的记录进⾏修改
update <tableName> set columnName=value [where conditions]
从数据表中提取满足特定条件的记录
## select 关键字后指定要显示查询到的记录的哪些列
select colnumName1[,colnumName2,colnumName3...] from <tableName> [where conditions];
## 如果要显示查询到的记录的所有列,则可以使⽤ * 替代字段名列表 (在项⽬开发中不建议使⽤*)
select * from user;
在删除、修改及查询的语句后都可以添加where子句(条件),用于筛选满⾜特定的添加的数据进⾏删除、修改和查询操作。
条件关系运算符
条件逻辑运算符
在where⼦句中,可以将多个条件通过逻辑预算(and or not )进⾏连接,通过多个条件来筛选要操作的数据。
在where子句的条件中,我们可以使⽤like关键字来实现模糊查询
在like关键字后的reg表达式中
将查询到的满足条件的记录按照指定的列的值升序/降序排列
order by columnName 表示将查询结果按照指定的列排序
多字段排序: 先满⾜第⼀个排序规则,当第⼀个排序的列的值相同时再按照第⼆个列的规则排序
SQL中提供了⼀些可以对查询的记录的列进行计算的函数——聚合函数
日期函数
当我们向日期类型的列添加数据时,可以通过字符串类型赋值(字符串的格式必须为
yyyy-MM-dd hh:mm:ss
),如果我们想要获取当前系统时间添加到日期类型的列,可以使⽤now()
或者sysdate()
。
字符串函数
分组——就是将数据表中的记录按照指定的类进行分组
语法
select 分组字段/聚合函数
from 表名
[where 条件]
group by 分组列名 [having 条件]
[order by 排序字段]
select 后使⽤ * 显示对查询的结果进行分组之后,显示每组的第⼀条记录(这种显示通常是⽆意义的)
select 后通常显示分组字段和聚合函数(对分组后的数据进⾏统计、求和、平均值等)
语句执行顺序:
当数据表中的记录比较多的时候,如果⼀次性全部查询出来显示给⽤户,用户的可读性体验性就不太好,因此我们可以将这些数据分页进行展示。
## 语法
select ...
from ...
where ...
limit param1,param2
MySQL是⼀个关系型数据库,不仅可以存储数据,还可以维护数据与数据之间的关系 ——通过在数据表中添加字段建⽴外键约束
数据与数据之间的 关联关系 分为四种:
⽅法1:
主键关联——两张数据表中主键相同的数据为相互对应的数据
⽅法2:
唯⼀外键 —— 在任意⼀张表中添加⼀个字段添加外键约束与另⼀张表主键关联,并 且将外键列添加唯⼀约束
⽅法: 在多的⼀端添加外键 ,与少的一端主键进行关联
⽅法: 额外创建⼀张关系表来维护多对多关联——在关系表中定义两个外键,分别与两个数据表的主键进行关联
将⼀个列添加外键约束与另⼀张表的主键(唯⼀列)进行关联之后,这个外键 约束的列添加的数据必须要在关联的主键字段中存在
案例:学⽣表 与 班级表
1.先创建班级表
CREATE TABLE classes (
class_id INT PRIMARY KEY auto_increment,
class_name VARCHAR ( 40 ) NOT NULL UNIQUE,
class_remark VARCHAR ( 200 )
);
2.创建学⽣表(在学⽣表中添加外键与班级表的主键进行关联)
## 【⽅式⼀】在创建表的时候,定义cid字段,并添加外键约束
# 由于cid 列 要与classes表的class_id进⾏关联,因此cid字段类型和⻓度要与class_id⼀致
CREATE TABLE students (
stu_num CHAR ( 8 ) PRIMARY KEY,
stu_name VARCHAR ( 20 ) NOT NULL,
stu_gender CHAR ( 2 ) NOT NULL,
stu_age INT NOT NULL,
cid INT,
CONSTRAINT FK_STUDENTS_CLASSES FOREIGN KEY ( cid )REFERENCES classes ( class_id )
);
## 【⽅式⼆】先创建表,再添加外键约束
CREATE TABLE students (
stu_num CHAR ( 8 ) PRIMARY KEY,
stu_name VARCHAR ( 20 ) NOT NULL,
stu_gender CHAR ( 2 ) NOT NULL,
stu_age INT NOT NULL,
cid INT
);
# 在创建表之后,为cid添加外键约束
ALTER TABLE students ADD CONSTRAINT FK_STUDENTS_CLASSES FOREIGN KEY ( cid ) REFERENCES classes ( class_id );
# 删除外键约束
ALTER TABLE students DROP FOREIGN KEY FK_STUDENTS_CLASSES;
当学⽣表中存在学⽣信息关联班级表的某条记录时,就不能对班级表的这条记录进行修 改ID和删除操作,如下:
SELECT * FROM classes;
SELECT * FROM students;
UPDATE classes SET class_id=5 WHERE class_name='Java';
DELETE FROM classes WHERE class_id=2;
如果⼀定要修改Java 的班级ID,该如何实现呢 ? 将引⽤Java班级id的学⽣记录中的cid修改为 NULL 在修改班级信息表中Java记录的 class_id 将学生表中cid设置为NULL的记录的cid重新修改为 Java这个班级的新的id
通过对DQL的学习,我们可以很轻松的从⼀张数据表中查询出需要的数据;在企业的应用开发中,我们经常需要从多张表中查询数据(例如:我们查询学生信息的时候需要同 时查询学生的班级信息),可以通过连接查询从多张数据表提取数据:
在MySQL中可以使用join实现多表的联合查询——连接查询,join按照其功能不同分为三个操作:
select ... from tableName1 inner join tableName2 ON 匹配条件 [where 条件];
笛卡尔积
内连接条件
两张表时⽤inner join连接查询之后生产的笛卡尔积数据中很多数据都是⽆意义的,我们如何消除无意义的数据呢? —— 添加两张进行连接查询时的条件 使用 on 设置两张表连接查询的匹配条件
结果:只获取两种表中匹配条件成立的数据,任何⼀张表在另⼀种表如果没有找到对应 匹配则不会出现在查询结果中)。
左连接:显示左表中的所有数据,如果在有右表中存在与左表记录满⾜匹配条件的数据,则 进行匹配;如果右表中不存在匹配数据,则显示为NULL
同上
如果在连接查询的多张表中存在相同名字的字段,我们可以使用 表名.字段名 来进行区分,如果表名太长则不便于SQL语句的编写,我们可以使⽤数据表别名
⼦查询 — 先进行⼀次查询,第⼀次查询的结果作为第二次查询的源/条件(第二次查询 是基于第⼀次的查询结果来进行的)
存储过程: 将能够完成特定功能的SQL指令进行封装(SQL指令集),编译之后存储在数据库服务器上,并且为之取⼀个名字,客户端可以通过名字直接调用这个SQL指令集,获取执行结果。
存储过程优点
存储过程的缺点
## 语法:
create procedure <proc_name>([IN/OUT args])
begin
-- SQL
end;
## 创建⼀个存储过程实现加法运算: Java语法中,⽅法是有参数和返回值的
## 存储过程中,是有输⼊参数 和 输出参数的
create procedure proc_test1(IN a int,IN b int,OUT c int)
begin
SET c = a+b;
end;
## 调⽤存储过程
## 定义变量@m
SET @m=0;
## 调用存储过程,将3传递给a,将2传递给b,将@m传递给c
CALL proc_test1 (3,2,@m);
## 显示变量值
SELECT @m FROM DUAL;
存储过程中的变量分为两种:
局部变量:定义在存储过程中的变量,只能在存储过程内部使用局部变量定义语法
## 局部变量要定义在存储过程中,⽽且必须定义在存储过程开始
declare <attr_name> <type> [default value];
## 局部变量定义示例:
CREATE PROCEDURE proc_test2 ( IN a INT, OUT r INT ) BEGIN
## 定义x int类型,默认值为0
DECLARE x INT DEFAULT 0;
## 定义y
DECLARE y INT DEFAULT 1;
SET x = a * a;
SET y = a / 2;
SET r = x + y;
END;
用户变量:相当于全局变量,定义的⽤户变量可以通过 select @attrName from dual 进行查询
## 用户变量会存储在mysql数据库的数据字典中(dual)
## 用户变量定义使⽤set关键字直接定义,变量名要以@开头
SET@n=1;
⽆论是局部变量还是用户变量,都是使用 set 关键字修改值
SET @n=1;
CALL proc_test2 (6,@n);
SELECT @n FROM DUAL;
用户变量使用注意事项
因为用户变量相当于全局变量,可以在SQL指令以及多个存储过程中共享,在开发中建议尽量少使用用户变量,用户变量过多会导致程序不易理解、难以维护。
MySQL存储过程的参数⼀共有三种:IN \ OUT \ INOUT
在存储过程中⽀持流程控制语句用于实现逻辑的控制
if-then-else
## 单分支:如果条件成立,则执行SQL
IF conditions THEN
## SQL
END IF;
## 双分支:如果条件成立则执行SQL1,否则执行SQL2
IF conditions THEN
## SQL1
ELSE
## SQL2
END IF;
case
CREATE PROCEDURE proc_test3 (IN a INT)
BEGIN
CASE a WHEN 1 THEN
## SQL1 如果a的值为1 则执行SQL1
WHEN 2 THEN
## SQL2 如果a的值为2 则执行SQL2
ELSE
## SQL (如果变量的值和所有when的值都不匹配,则执行else中的这个SQL)
END CASE;
END;
while
CREATE PROCEDURE proc_test4 (IN num INT)
BEGIN
DECLARE i INT;
SET i=0;
WHILE i< num DO
-- SQL
SET i=i+1;
END WHILE;
END;
CALL proc_test4(4);
repeat
CREATE PROCEDURE proc_test5 (IN num INT)
BEGIN
DECLARE i INT;
SET i=1;
REPEAT
-- SQL
SET i=i+1;
UNTIL i> num
END REPEAT;
END;
CALL proc_test5 (4);
loop
CREATE PROCEDURE proc_test6 (IN num INT)
BEGIN
DECLARE i INT;
SET i=0;
myloop : LOOP-- SQL
INSERT INTO classes (class_name) VALUES (CONCAT('HTML',i ));
SET i=i+1;
IF i=num THEN
LEAVE myloop;
END IF;
END LOOP;
END;
CALL proc_test6 (5);
存储过程是属于某个数据库的,也就是说当我们将存储过程创建在某个数据库之后,只能在当前数据库中调用此存储过程。
查询存储过程:查询某个数据库中有哪些存储过程
## 根据数据库名,查询当前数据库中的存储过程
SHOW PROCEDURE STATUS WHERE db='mysql_test';
-- 查询存储过程的创建细节
SHOW CREATE PROCEDURE mysql_test.proc_test1;
修改存储过程指的是修改存储过程的特征/特性
ALTER PROCEDURE<proc_name> 特征1 [特征2 特征3 ....]
存储过程的特征参数:
ALTER PROCEDURE proc_test1 READS SQL DATA;
## 删除存储过程
## drop 删除数据库中的对象 数据库、数据表、列、存储过程、视图、触发器、索引....
## delete 删除数据表中的数据
DROP PROCEDURE proc_test1;
游标可以用来依次取出查询结果集中的每⼀条数据——逐条读取查询结果集中的记录
游标的使用步骤
## 1、声明游标
DECLARE cursor_nanme CURSOR FOR select_statement;
## 2、打开游标
open mycursor;
## 3、使用游标,使用游标:提取游标当前指向的记录(提取之后,游标⾃动下移)
FETCH mycursor INTO bname,bauthor,bprice;
## 4、关闭游标
CLOSE mycursor;
触发器,就是⼀种特殊的存储过程。触发器和存储过程⼀样是⼀个能够完成特定功能、存储在数据库服务器上的SQL片段,但是触发器无需调用,当对数据表中的数据执行DML操作时自动触发这个SQL⽚段的执行,无需⼿动调用。
在MySQL,只有执行insert
、delete
、update
操作才能触发触发器的执行。
## 创建触发器
create trigger tri_name
<before|after> -- 定义触发时机
<insert|delete|update> -- 定义DML类型
ON <table_name>
for each row -- 声明为⾏级触发器(只要操作⼀条记录就触发触发器执⾏⼀
次)
sql_statement -- 触发器操作
## 查看触发器
SHOW TRIGGERS;
## 删除触发器
DROP TRIGGER tri_test1;
触发器用于监听对数据表中数据的insert、delete、update操作,在触发器中通常处理⼀些DML的关联操作;我们可以使用 NEW 和 OLD 关键字在触发器中获取触发这个触发器的DML操作的数据
优点
缺点
使用建议
视图,就是由数据库中⼀张表或者多张表根据特定的条件查询出得数据构造成得 虚拟表
## 创建视图
CREATE VIEW <view_name> AS <tableName>
视图是虚拟表,查询视图的数据是来源于数据表的。当对视图进行操作时,对原数据表中的数据是否由影响呢?
-- 查询视图结构
desc <view_name>
-- ⽅式1
create OR REPLACE view <view_name>
AS
select * from students where stu_gender='⼥';
-- ⽅式2
alter view <view_name>
AS
select * from students where stu_gender='男';
删除数据表时会同时删除数据表中的数据,删除视图时不会影响原数据表中的数据
-- 删除视图
drop view <view_name>;
数据库是用来存储数据,在互联网应用中数据库中存储的数据可能会很多(大数据), 数据表中数据的查询速度会随着数据量的增长逐渐变慢 ,从而导致响应用户请求的速度变慢——用户体验差,我们如何提⾼数据库的查询效率呢?
索引,就是用来提⾼数据表中数据的查询效率的。
索引,就是将数据表中某⼀列\某几列的值取出来构造成便于查找的结构进行存储,生成数据表的目录
当我们进行数据查询的时候,则先在目录中进行查找得到对应的数据的地址,然后再到数据表中根据地址快速的获取数据记录,避免全表扫描。
MySQL中的索引,根据创建索引的列的不同,可以分为:
在创建数据表时,将字段声明为主键(添加主键约束),会⾃动在主键字段创建主键索引;
在创建数据表时,将字段声明为唯⼀键(添加唯⼀约束),会⾃动在唯⼀字段创建唯⼀索引;
## 创建唯⼀索引: 创建唯⼀索引的列的值不能重复
-- create unique index on 表名(列名);
create unique index idx_name on user(name);
## 创建普通索引: 不要求创建索引的列的值的唯⼀性
-- create index on 表名(列名);
create index idx_age on user(age);
## 创建组合索引
-- create index on 表名(列名1, 列名2...);
create index idx_gender_tel on user(gender, tel);
## 全⽂索引
-- MySQL 5.6 版本新增的索引,可以通过此索引进⾏全⽂检索操作,因为MySQL全⽂检索不⽀持中⽂,
-- 因此这个全⽂索引不被开发者关注,在应⽤开发中通常是通过搜索引擎(数据库中间件)实现全⽂检索
-- create fulltext index on 表名(字段名);
create fulltext index idx_address on user(address);
索引创建完成之后⽆需调用,当根据创建索引的列进行数据查询的时候,会⾃动使用索引;
组合索引需要根据创建索引的所有字段进行查询时触发。
## 查看查询语句的查询规划
-- explain 查询sql语句
explain select * from user where id='10001';
-- show create table ;
show create table user;
-- 查询数据表的索引
show indexes from user;
-- 查询索引
show keys from user;
-- 删除索引:索引是建⽴在表的字段上的,不同的表中可能会出现相同名称的索引
-- 因此删除索引时需要指定表名
-- drop index on ;
drop index idx_name on user;
优点
缺点
注意事项
1.数据表中数据不多时,全表扫⾯可能更快吗,不要使⽤索引;
2.数据量⼤但是DML操作很频繁时,不建议使用索引;
3.不要在数据重复读高的列上创建索引(性别);
4.创建索引之后,要注意查询SQL语句的编写,避免索引失效。