第四篇 MySql常用命令
数字类型
使用原则:根据业务来决定,一般来时能用小范围的就别用大范围的。
日期类型
常用的:DATATIME 和 TIMESTAMP两个
字符串类型
常用的:CHAR 和 VARCHAR 两个
表操作 - sql基础
通过Navicat创建表
因为可视化操作效率高,所以通过Navicat来创建,当然也可以通过命令行来创建表
id:一般要设置为自动递增
通过命令创建表
CREATE TABLE `order` ( `id` int(10) NOT NULL AUTO_INCREMENT, `phone_num` varchar(11) DEFAULT NULL COMMENT '手机号', `address` varchar(256) DEFAULT NULL COMMENT '地址', `price` decimal(10,0) DEFAULT NULL COMMENT '订单价格', `type` tinyint(2) DEFAULT NULL COMMENT '订单类型', `create_time` datetime DEFAULT NULL COMMENT '创建时间', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=16 DEFAULT CHARSET=utf8;
基本的sql操作 - 增删改查
增
id 一般不需要用户来操作
单条数据插入
INSERT INTO `order` (phone_num,address,price,type,create_time) VALUES ('13331039702','北京','19.9', '1','2019-10-16 18:00:09');
批量数据插入
INSERT INTO `order` (phone_num,address,price,type,create_time) VALUES
('13331039702','北京','19.9', '1','2019-10-16 18:00:09'),
('13331039703','上海','119.9', '2','2019-10-18 19:00:09'),
('13331039704','广州','129.9', '2','2019-10-19 20:00:09');
删
DELETE FROM `order` WHERE id = 1;
查
基础查询
SELECT * FROM `order` WHERE address='北京';
SELECT phone_num, price FROM `order` WHERE address='北京';
模糊查询
SELECT * FROM `order` WHERE phone_num LIKE '13331%';
SELECT * FROM `order` WHERE phone_num LIKE '%9703';
SELECT * FROM `order` WHERE phone_num LIKE '%1039%';
范围查询
select * from `order` where price BETWEEN 9 and 20; -- [9,20]闭区间,包含
select * from `order` where price in (19.9, 119.9); -- 查询到内容必须是()内的值
select * from `order` where price not IN (20, 30,40); -- 查到的结果不是()内容的值
改
UPDATE `order` SET address = '杭州' WHERE id=3; -- 修改单个字段
UPDATE `order` SET address = '杭州',type = 2 WHERE id=4; -- 修改多个字段
mysql里的运算符
算数运算符
比较运算符
逻辑运算符
聚合函数
max(最大)、min(最小)、avg(平均)、sum(求和)、count(总数)
SELECT MAX(price) FROM `order` WHERE address = '北京'; -- 符合条件的最大值
SELECT MIN(price) FROM `order` WHERE address = '北京'; -- 符合条件的最小值
SELECT SUM(price) FROM `order` WHERE address = '北京'; -- 符合条件的总和
SELECT AVG(price) FROM `order` WHERE address = '北京'; -- 符合条件的平均值
SELECT COUNT(*) FROM `order` WHERE address = '杭州'; -- 统计符合条件的数据的行数
排序
根据某个字段把查询出来的结果进行排序
-- 按照价格字段排序
SELECT * FROM `order` ORDER BY price; -- 默认是按照升序排列的
SELECT * FROM `order` ORDER BY price ASC; -- asc表示升序,同默认
SELECT * FROM `order` ORDER BY price DESC; -- desc表示倒序
去重
去除重复的数据
-- 把价格相同的数据进行去重
SELECT DISTINCT(price) FROM `order` ;
限制
如果只想查询几条(10,20)数据,可以通过limit进行限制
在分页功能中大量使用
SELECT * FROM `order` LIMIT 4; -- 从查询结果里只取前4条数据
SELECT * FROM `order` LIMIT 0,3; -- 0表示从第一个位置开始往后取3条数据
SELECT * FROM `order` LIMIT 3,4; -- 3表示从第三个位置开始取4条数据,不包给3的位置
分组
按照表中的某一个或者某多个字段,将数据进行分组,一般用于将数据进行分类汇总
需求1:得出每个城市下面的总价格
解析: 需要先根据address进行分组,然后通过聚合函数 sum来求出每个城市的总价格
-- 根据单个条件分组 SELECT address, SUM(price) from `order` GROUP BY address;
查询结果如下
需求2:得出每个城市下面不同的type的总金额
解析:分析需要根据城市和type进行分组,然后通过聚合函数求出总函数
-- 根据多个条件分组 SELECT address, type, SUM(price) from `order` GROUP BY address, type;
注意:
使用 group by 的sql语句,select 后的字段,只能是group by后的字段,如果想要展示其他列,必须要给该列使用聚合函数;
否则默认展示分组里的第一行数据。
分组过滤
having对分组之后的数据进行过滤
需求:对Order表的数据,按照区域和类型分组,展示每个区域订单总金额>400的数据
SELECT address, type, SUM(price) from `order`
GROUP BY address, type HAVING SUM(price)>400;
SQL语句的执行顺序
from 哪个表 where 什么条件 group by 分组条件 having 过滤条件select 要查询的字段 order by 排序条件
MySql约束
主键
MySql主键(Primary Key)是唯一标识表中每一行的列或者一组列。当地定义表的主键时,必须遵循以下规则:
- 主键必须包含唯一值。如果主键由多个列组成,则这些列中的值的组合必须是唯一的。
- 主键列不能包含null值。这意味着必须使用 not null 属性声明主键列。如果没有指定 not null, mysql将强制为主键列为 not null.
- 一张表只有一个主键,主键字段的数据类型必须为整数类型。
可以在创建表的时候指定主键
主要作用:
- 保证数据不重复
- 能够提升性能
CREATE TABLE `order` (
`id` int(10) NOT NULL AUTO_INCREMENT PRIMARY KEY,
`phone_num` varchar(11) DEFAULT NULL COMMENT '手机号',
`address` varchar(256) DEFAULT NULL COMMENT '地址',
`price` decimal(10,0) DEFAULT NULL COMMENT '订单价格',
`type` tinyint(2) DEFAULT NULL COMMENT '订单类型',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
) ENGINE=InnoDB AUTO_INCREMENT=16 DEFAULT CHARSET=utf8;
外键
外键表示一个表中的一个字段被另一个表中的一个字段引用,外键可以在数据库层面保证数据的完整性。
外键的主要是用来做数据约束的。
对外键的理解
举例:
在order表里有个user_id 字段,这个字段是来自于 user表的。
order表里所有的user_id的值都必须在user表里。
下面order表里出现一个user_id的值是8在user表里没有的,说明程序有问题了。这种问题就可以在数据库层面通过外键来约束,如果要给order表插入的数据里user_id在user表里不存在,就会报错,无法插入成功。
user表
order表
设置外键(Navicat)
哪个表引用了其他表里的字段,就要给哪个表设置外键。
举例order表里的user_id字段是引用的user表里的id字段,所有需要给order表设置外键。
按照上面的设置保存的时候报下面的错误,这是因为在order表里有一个数据,它的user_id值是8,但是在user表里没有id为8的数据,所以会报错。
解决办法:在order表里删除这条数据再保存就可以了
设置外键(命令行)
CREATE TABLE `order` (
`id` int(10) NOT NULL AUTO_INCREMENT,
`phone_num` varchar(11) DEFAULT NULL COMMENT '手机号',
`address` varchar(256) DEFAULT NULL COMMENT '地址',
`price` decimal(10,0) DEFAULT NULL COMMENT '订单价格',
`type` tinyint(2) DEFAULT NULL COMMENT '订单类型',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`user_id` int(10) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `fk_user_id` (`user_id`),
CONSTRAINT `fk_user_id` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=16 DEFAULT CHARSET=utf8;
验证外键设置是否生效
1.先在order表里插入一条数据,user_id在user表里不存在,会报下面的错误,数据不能插入
INSERT into `order` (user_id, address) VALUES (14, '上海');
错误提示
1452 - Cannot add or update a child row: a foreign key constraint fails (`study`.`order`, CONSTRAINT `fk_user_id` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`)), Time: 0.036000s
2.在user表里删除一个在order表里有订单的用户,会删除失败,报下面的错误提示。
如果要删除这个用户,必须先从order表里把这个用户的订单数据删除掉才可以。
SQL高级
等值连接(内连接)inner join
以某字段为条件,取左表和右表中同时存在相同数据的行,相当于两个表的交集
需求:查询一下order表里每个订单所属的用户信息
SELECT * FROM `order` INNER JOIN `user` ON order.user_id = user.id;
-- `order` o: 表示给order表取个别名为o
SELECT * FROM `order` o INNER JOIN `user` u ON o.user_id = u.id;
查询到的结果
总结:
内连接会把两个表里都存在的数据查询出来,即取的两个表的交集数据。
左连接 left join
以某字段为连接条件,取左表中的全部数据+右表与该字段对应的数据,可能会有某些数据在左表存在但是右表不存在的情况。
通俗理解就是:左连接是以左表为基础,左表表里符合条件的数据都展示,但是对应的行在右表的表里可能没有数据。
SELECT * FROM `order` o LEFT JOIN `user` u ON o.user_id = u.id;
右链接 right join
以某字段为连接条件,取右表中的全部数据+左表与该字段对应的数据,可能会有某些数据在右表存在但是左表不存在的情况。
SELECT * FROM `order` o RIGHT JOIN `user` u ON o.user_id = u.id;
查询结果:
以右表为基础,左边的表里可能没有数据
嵌套查询
多个select语句进行嵌套,嵌套的位置可以在select后,from后,where后。
需求:查询地址为北京的用户的邮箱
- 可以用上面的连接查询来实现
- 也可以通过嵌套查询来实现。先查出北京的用户的id,然后从用户表里查到邮箱
这里演示第二种方法
-- 放在where后
SELECT user_name,email FROM `user` WHERE id in (SELECT user_id FROM `order` WHERE address = '北京');
-- 放在from ,一定要起个别名,这里是m,否则会报错
SELECT m.address from (SELECT address,price FROM `order`) m;
-- 放在select后,(SELECT address from `order` WHERE user_id=1)查到的数据只能是一行,并且是一列
SELECT (SELECT address from `order` WHERE user_id=1), phone_num from `user`;
Union
可以将多个select语句的结果合并为一个,合并后会删除重复的数据。
是可以把两个完全独立的表的查询的结果进行合并;而连接和嵌套则是对有关联的表进行查询和关联。
Union all
可以将多个select语句的结果合并为一个,合并后不会删除重复的数据
注意:union 和 union all 语句中,两个select查询的字段数量必须一样
-- 从user表里查询手机号
SELECT phone_num from user;
-- 从order表里查询手机号
SELECT phone_num from `order`;
-- 把上面两个表的查询结果合并然后去重
SELECT phone_num from user UNION SELECT phone_num from `order`;
-- 把两个表的查询结果合并但是不去重
SELECT phone_num from user UNION ALL SELECT phone_num from `order`;
练习:统计每个地区订单总金额占全国订单总金额的比例,按照倒序排列,取占比最高的前3位。
-- 分解:每个地区的总金额
SELECT address, SUM(price) as region_price from `order` GROUP BY address;
-- 分解:全国的总金额
SELECT SUM(price) as all_price FROM `order`;
-- 最终结果
SELECT
tmp.address,
tmp.region_price / tmp.all_price * 100 AS ratio
FROM
( SELECT address, SUM( price ) AS region_price, ( SELECT SUM( price ) FROM `order` ) AS all_price FROM `order` GROUP BY address ) tmp
ORDER BY
ratio DESC
LIMIT 3;
索引
MySql表字段添加索引可以单独提高MySQL的查询速度。数据库就好像一本字典,那么索引就是字典的目录。一般会针对where条件后面的字段添加索引
通过Navicat添加索引
添加普通索引
-- user:是表名
-- phone_num_index:是索引名称,随便起名字的
-- phone_num:索引字段
ALTER TABLE `user` ADD INDEX phone_num_index(phone_num);
添加唯一索引
ALTER TABLE `user` ADD UNIQUE INDEX phone_num_index(phone_num);
删除索引
-- 根据索引名去删除索引的
DROP INDEX phone_num_index on `user`;
复制表
MySQL 可以通过 SQL语句快速复制表,并完成数据的复制。
主要是对表进行备份,复制出来的表可以进行数据测试,处理等,避免对原始表的污染
Navicat复制表
复制表
create table user_copy like user;
复制数据
insert into user_copy select * from user;
常用函数
字符串函数
1.concat()函数
作用:将两个或多个字符串组成或者拼接成一个字符串
-- 固定字符串拼接
SELECT CONCAT('test',2,'ok');
-- 动态字符串拼接
SELECT CONCAT(user_name, ',电话是:',phone_num, ',年龄是:',age) FROM `user`;
查询结果
2.length()函数
作用:获取字符串的长度
SELECT LENGTH(phone_num) FROM `user`;
3.replace()函数
作用:搜索并替换字符串中的子字符串
-- email 替换字段;mx 被替换内容; test 将mx替换成的内容
SELECT REPLACE(email, 'mx','test') FROM `user`;
4.substring()函数
作用:从具有特定长度的位置开始提取一个子字符串
需求:获取每个用户手机号的后四位
-- phone_num 处理字段;从第8位开始 的 后 4位
SELECT SUBSTRING(phone_num,8,4) FROM `user`;
时间函数
1.curdate()函数
作用:返回当前日期
SELECT CURRENT_DATE(); -- 结果: 2020-04-19
2.now()函数
作用:返回当前日期和时间
SELECT NOW(); -- 结果:2020-04-19 09:32:09
3.year()函数
作用:返回日期中的年份
SELECT YEAR(create_time) FROM `user`; -- 结果:2020
4.month()函数
作用:返回日期中的月份
SELECT MONTH(create_time) FROM `user` -- 结果:具体月份
5.day()函数
作用:返回日期中的天数
SELECT DAY(create_time) FROM `user`;
6.时分秒函数
SELECT HOUR(create_time) FROM `user`;
SELECT MINUTE(create_time) FROM `user`;
SELECT SECOND(create_time) FROM `user`;
数据处理函数
1.rand()函数
作用:返回0~1之间随机小数
SELECT RAND(); -- 0.6606990561454548 每次运行都会变化
SELECT RAND() * 100; -- 66.43990561454548 每次运行都会变化
2.floor()函数
作用:小数取整
SELECT FLOOR(4.99834); -- 4
SELECT FLOOR(RAND() * 100); -- 0~100内的整数
SELECT FLOOR(10 + RAND() * 90); -- 10~100内的整数
存储过程
存储过程(Stored Procedure)是在大型数据库系统中,一组为了完成特定功能的SQL语句集,它存储在数据库中,一次编译后永久有效,用户通过指定存储过程的名字并给出参数(如果该存储过程带有参数)来执行它。存储过程是数据库中的一个重要对象
总结:存储过程 = 逻辑 + SQL
While循环语法
while 条件 do
sql语句;
end while;
if判断语法
if 条件 then
sql语句;
else
sql语句;
end if;
存储过程实战
需求:构造10000个测试账号。
思路: 注册的账号一般都是保存在数据库里的,所以可以直接在数据库写insert语句插入账号就行。 下面是一条单个数据,插入已经成功了,但是数据是写死的;所以需要通过上面的知识点综合运用,写一个存储过程,来动态生成每个字段对应的值,完成10000条数据的插入。
INSERT INTO `user` (user_name,`password`,age, gender,phone_num,email,create_time)
VALUES ('白衣秀才', '123321', '36','1', '13200001000', 'wanglun@163.com', NOW());
在Navicat里写存储过程
-- number 是参数,想造多少条数据通过number参数传进去就可以了
CREATE DEFINER=`root`@`%` PROCEDURE `createUsers`(number int)
BEGIN
-- 定义所需要的变量
DECLARE i INT(6) DEFAULT 0; -- 声明变量i,整型,长度为6,起始值为0
DECLARE u_name VARCHAR(10); -- 声明user_name变量,字符串类型,长度10
DECLARE u_age INT(4); -- 声明年龄变量
DECLARE u_gender INT(2); -- 声明年龄变量
DECLARE u_phone_num VARCHAR(11);
DECLARE u_email VARCHAR(20);
WHILE i<number DO
-- 如果i是偶数,性别设置为0;为奇数,就设置为1;这样能实现性别一半对一半
IF i%2=0 THEN
SET u_gender = 0;
ELSE
SET u_gender = 1;
END IF;
-- set 都是赋值操作
set u_name = CONCAT('test_',i); -- 拼接一个用户名
set u_age = FLOOR(RAND()*100); -- 随机数*100,再取整
SET u_phone_num = CONCAT('133310',i+10000);-- 构造手机号
SET u_email = CONCAT(u_name,'@163.com');
INSERT INTO `user` (user_name,`password`,age, gender,phone_num,email,create_time)
VALUES (u_name, '123321', u_age, u_gender, u_phone_num, u_email, NOW());
SET i = i+1; -- 在存储过程里,所有赋值类操作,前面都必须加个set
END WHILE;
END
数据导入与导出
通过Navicat导出导入
导出
1.导出整个库
2.导出单张表
3.导出某些字段(导出向导)
按照下面的图示步骤即可完成
导入
在数据库上右键-运行SQL文件, 选择导出的sql文件,然后按照提示即可
通过命令导入导出
导出命令
导出借助的是mysql提供的工具mysqldump
,在mysql的bin目录下面,所以执行导出操作的时候要先进入到bin目录下面.
我用的是阿里云,所以先远程连接到阿里云,然后进入mysql的bin目录
cd /usr/bin
再执行导出命令,导出整个study库,导出到/usr/目录下面
-- 导出整个库
mysqldump -u root -p study > /usr/study.sql
-- 导出某张表,在库名study后空格,表名user
mysqldump -u root -p study user> /usr/user.sql
导入命令
导入因为直接用的是命令,需要先把被导入文件user.sql复制到mysql的bin目录下面,然后登录进入mysql
mysql -u root -p -- 登录到数据库
use study; -- 切换到要导入表的库
source user.sql; -- 导入user表