【极客时间】MySQL 必知必会-20230901
03 | 表:怎么创建和修改数据表?
新增数据表
CREATE DATABASE demo;CREATE TABLE goodsmaster (barcode TEXT,goodsname TEXT,price DOUBLE, itemnumber INT PRIMARY KEY AUTO_INCREMENT);INSERT INTO demo.goodsmaster (barcode, goodsname,price) VALUES ('002','笔',0.44);SELECT * from demo.goodsmaster;SELECT SUM(price)
FROM demo.goodsmaster;
修改数据表
ALTER TABLE demo.goodsmaster
MODIFY COLUMN price DECIMAL(5,2);CREATE TABLE demo.inporthead
(listnumber INT,supplierid INT,stocknumber INT,importtype INT DEFAULT 1,quantity DECIMAL(10,3),
importvalue DECIMAL(10,2),record INT,recordingdate DATETIME);INSERT INTO demo.inporthead
(listnumber,supplierid,stocknumber,quantity,importvalue,recorder,recordingdate)
VALUES(3456,1,1,10,100,1,'2020-12-10');INSERT INTO demo.goodsmaster
(itemnumber,barcode,goodsname,specification,unit,price)
VALUES(100,'0003','测试1','','个',10);INSERT INTO demo.goodsmaster
(barcode,goodsname,specification,unit,price)
VALUES('0003','测试1','','个',10);CREATE TABLE demo.importheadhist
LIKE demo.importhead;ALTER TABLE demo.importheadhist ADD confirmer INT;
ALTER TABLE importheadhist ADD confirmdate DATETIME;DESCRIBE demo.importheadhist;ALTER TABLE demo.importheadhist CHANGE quantity importquantity DOUBLE;ALTER TABLE demo.importheadhist MODIFY importquantity DECIMAL(10,3);ALTER TABLE demo.importheadhist ADD suppliername TEXT AFTER supplierid;
总结
CREATE TABLE
(
字段名 字段类型 PRIMARY KEY
);
CREATE TABLE
(
字段名 字段类型 NOT NULL
);
CREATE TABLE
(
字段名 字段类型 UNIQUE
);
CREATE TABLE
(
字段名 字段类型 DEFAULT 值
);
-- 这里要注意自增类型的条件,字段类型必须是整数类型。
CREATE TABLE
(
字段名 字段类型 AUTO_INCREMENT
);
-- 在一个已经存在的表基础上,创建一个新表
CREATE TABLE demo.importheadhist LIKE demo.importhead;
-- 修改表的相关语句
ALTER TABLE 表名 CHANGE 旧字段名 新字段名 数据类型;
ALTER TABLE 表名 ADD COLUMN 字段名 字段类型 FIRST|AFTER 字段名;
ALTER TABLE 表名 MODIFY 字段名 字段类型 FIRST|AFTER 字段名;
04 | 增删改查:如何操作表中的数据?
删
DELETE
FROM demo.goodsmaster
WHERE itemnumber=5;
增
INSERT INTO 表名 (字段名)
SELECT 字段名或值
FROM 表名
WHERE 条件
INSERT INTO importhead_copy (listnumber,supplierid,stocknumber,importtype,quantity,importvalue,recorder,recordingdate)
SELECT listnumber,supplierid,stocknumber,importtype,quantity,importvalue,recorder,recordingdate
FROM importhead
WHERE recordingdate = '2023-03-03 00:00:00';
DESCRIBE demo.importhead_copy;
DELETE FROM 表名WHERE 条件
DELETE FROM demo.goodsmaster;DELETE FROM demo.goodsmaster
WHERE itemnumber > 1;
改
UPDATE 表名
SET 字段名=值
WHERE 条件
update importhead_copy
SET listnumber=100
WHERE supplierid = 1;
查
SELECT *|字段列表
FROM 数据源
WHERE 条件
GROUP BY 字段
HAVING 条件
ORDER BY 字段
LIMIT 起始点,行数
SELECT * FROM demo.goodsmaster
ORDER BY barcode ASC,price DESC;
SELECT * FROM demo.goodsmaster
ORDER BY barcode ASC,price DESC
LIMIT 1,2;
INSERT INTO demo.goodsmaster SELECT *FROM demo.goodsmaster1 as aON DUPLICATE KEY UPDATE barcode = a.barcode,goodsname=a.goodsname;
复习
INSERT INTO 表名 [(字段名 [,字段名] ...)] VALUES (值的列表);INSERT INTO 表名 (字段名)
SELECT 字段名或值
FROM 表名
WHERE 条件DELETE FROM 表名
WHERE 条件UPDATE 表名
SET 字段名=值
WHERE 条件SELECT *|字段列表
FROM 数据源
WHERE 条件
GROUP BY 字段
HAVING 条件
ORDER BY 字段
LIMIT 起始点,行数
05 | 主键:如何正确设置主键?
设定主键
CREATE TABLE demo.membermaster
(
cardno CHAR(8) PRIMARY KEY,
membername TEXT,
memberphone TEXT,
memberid TEXT,
memberaddress TEXT,
sex TEXT,
birthday DATETIME
);insert into demo.membermaster
(cardno,membername,memberphone,memberid,memberaddress,sex,birthday)
VALUES('10000001','张三','13620888888','110123200001017890','北京','男','2000-01-01');
关联查询
SELECT b.membername,c.goodsname,a.quantity,a.salesvalue,a.transdate
FROM demo.trans AS a
JOIN demo.membermaster AS b
JOIN demo.goodsmaster AS c
ON (a.cardno = b.cardno AND a.itemnumber = c.itemnumber);
更新表格信息
UPDATE demo.membermaster
SET membername = '王五',
memberphone = '13698765432',
memberid = '475145197001012356',
memberaddress='天津',
sex='女',
birthday= '1970-01-01'
WHERE cardno = '10000001'
修改主键
ALTER TABLE demo.membermaster
DROP PRIMARY KEYALTER TABLE demo.membermaster
ADD id INT PRIMARY KEY AUTO_INCREMENT;ALTER TABLE demo.trans
ADD memberid INT;UPDATE demo.trans AS a,demo.membermaster AS b
SET a.memberid=b.id
WHERE a.transactionno > 0
AND a.cardno = b.cardno;
关联查询2
SELECT b.membername,c.goodsname,a.quantity,a.salesvalue,a.transdate
FROM demo.trans AS a
JOIN demo.membermaster AS b
JOIN demo.goodsmaster AS c
ON (a.memberid = b.id AND a.itemnumber = c.itemnumber);
06 | 外键和连接:如何做关联查询?
复习
-- 定义外键约束:
CREATE TABLE 从表名
(
字段 字段类型
....
CONSTRAINT 外键约束名称
FOREIGN KEY (字段名) REFERENCES 主表名 (字段名称)
);
ALTER TABLE 从表名 ADD CONSTRAINT 约束名 FOREIGN KEY 字段名 REFERENCES 主表名 (字段名);-- 连接查询
SELECT 字段名
FROM 表名 AS a
JOIN 表名 AS b
ON (a.字段名称=b.字段名称);SELECT 字段名
FROM 表名 AS a
LEFT JOIN 表名 AS b
ON (a.字段名称=b.字段名称);SELECT 字段名
FROM 表名 AS a
RIGHT JOIN 表名 AS b
ON (a.字段名称=b.字段名称);
建立主从表
CREATE TABLE demo.importhead (listnumber INT PRIMARY KEY,supplierid INT,stocknumber INT,importtype INT,importquantity DECIMAL(10 , 3 ),importvalue DECIMAL(10 , 2 ),recorder INT,recordingdate DATETIME
);CREATE TABLE demo.importdetails
(listnumber INT,itemnumber INT,quantity DECIMAL(10,3),importprice DECIMAL(10,2),importvalue DECIMAL(10,2),-- 定义外键约束,指出外键字段和参照的主表字段CONSTRAINT fk_importdetails_importheadFOREIGN KEY (listnumber) REFERENCES importhead (listnumber)
);
内连接
SELECT a.transactionno,a.itemnumber,a.quantity,a.price,a.transdate,b.membername
FROM demo.trans AS a
JOIN demo.membermaster AS b ON (a.cardno = b.cardno);
左链接
SELECT a.transactionno,a.itemnumber,a.quantity,a.price,a.transdate,b.membername
FROM demo.trans AS a
LEFT JOIN demo.membermaster AS b -- LEFT JOIN,以demo.transaction为主
ON (a.cardno = b.cardno);
右链接
SELECT a.transactionno,a.itemnumber,a.quantity,a.price,a.transdate,b.membername
FROMdemo.membermaster AS bRIGHT JOINdemo.trans AS a ON (a.cardno = b.cardno); -- RIGHT JOIN,顺序颠倒了,还是以demo.trans为主
我的实践
- 左链接查询在职人员的passlist通过情况
SELECT a.emplid,a.name_a,a.deptid,b.FUNCTION_NAME,b.PASS_ALL
FROMdemo.season_people AS a
LEFT JOINdemo.season_passlist AS b ON (a.emplid = b.MPLOYEE_ID);
- 内链接查询工号一致的通过情况
SELECT a.emplid,a.deptid,b.FUNCTION_NAME,b.PASS_ALL
FROMdemo.season_people AS a
JOINdemo.season_passlist AS b ON (a.emplid = b.MPLOYEE_ID);
- 左链接查询三表
SELECT a.emplid,a.deptid,b.FUNCTION_NAME,b.PASS_ALL,c.course,c.present,c.score
FROMdemo.season_people AS a
LEFT JOINdemo.season_passlist AS b ON (a.emplid = b.MPLOYEE_ID)
LEFT JOINdemo.season_training AS c ON (a.emplid = c.employid)
- 增加where条件
SELECT a.emplid,a.deptid,b.FUNCTION_NAME,b.PASS_ALL,c.course,c.present,c.score
FROMdemo.season_people AS a
LEFT JOINdemo.season_passlist AS b ON (a.emplid = b.MPLOYEE_ID)
LEFT JOINdemo.season_training AS c ON (a.emplid = c.employid)
WHERE b.PASS_ALL = 'Y'
- 增加group by条件,看起来会丢失明细数据,需要匹配聚合信息。
SELECT a.*,COUNT(a.emplid)
FROMdemo.season_people AS a
GROUP BY a.deptid
07 | 条件语句:WHERE 与 HAVING有什么不同?
WHERE
SELECT DISTINCT b.goodsname
FROM demo.transactiondetails AS a
JOIN demo.goodsmaster AS b
ON (a.itemnumber = b.itemnumber)
WHERE a.salesvalue > 50;
GROUP BY
- 多表交叉
SELECT a.transdate,b.operatorname,d.goodsname,c.quantity,c.price,c.salesvalue
FROMdemo.transactionhead AS a
JOINdemo.operator AS b ON (a.operatorid = b.operatorid)
JOINdemo.transactiondetails AS c ON (a.transactionid = c.transactionid)JOINdemo.goodsmaster AS d ON (d.itemnumber = c.itemnumber);
- 如果我想看看每天的销售数量和销售金额,可以按照一个字段“transdate”对数据进行分组和统计:
SELECT a.transdate,sum(b.quantity),sum(b.salesvalue)
FROMdemo.transactionhead AS a
JOINdemo.transactiondetails AS b ON (a.transactionid = b.transactionid)
GROUP BY a.transdate
- 如果我想看每天、每个收银员的销售数量和销售金额,就可以按 2 个字段进行分组和统计,分别是“transdate”和“operatorname”:
SELECT a.transdate,c.operatorname,sum(b.quantity),sum(b.salesvalue)
FROMdemo.transactionhead AS a
JOINdemo.transactiondetails AS b ON (a.transactionid = b.transactionid)
JOINdemo.operator AS c ON (a.operatorid = c.operatorid)
GROUP BY a.transdate
HAVING
SELECT DISTINCT b.goodsname
FROM demo.transactiondetails AS a
JOIN demo.goodsmaster AS b
ON (a.itemnumber = b.itemnumber)
GROUP BY b.goodsname
HAVING MAX(a.salesvalue)>50;
区别
第一个区别是,如果需要通过连接从关联表中获取需要的数据,WHERE 是先筛选后连接,而 HAVING 是先连接后筛选。
第二个区别是,WHERE 可以直接使用表中的字段作为筛选条件,但不能使用分组中的计算函数作为筛选条件;HAVING 必须要与 GROUP BY 配合使用,可以把分组计算的函数和分组字段作为筛选条件。
假如超市经营者提出,要查询一下是哪个收银员、在哪天卖了 2 单商品。这种必须先分组才能筛选的查询,用 WHERE 语句实现就比较难,我们可能要分好几步,通过把中间结果存储起来,才能搞定。但是用 HAVING,则很轻松,代码如下:
SELECT a.transdate,count(b.itemnumber),c.operatorname
FROM demo.transactionhead AS a
JOIN demo.transactiondetails AS b
ON (a.transactionid = b.transactionid)
JOIN demo.operator AS c
ON (a.operatorid = c.operatorid)
GROUP BY a.transdate
HAVING COUNT(b.itemnumber)=2;
WHERE 和 HAVING 也不是互相排斥的,我们可以在一个查询里面同时使用 WHERE 和 HAVING。举个例子,假设现在我们有一组销售数据,包括交易时间、收银员、商品名称、销售数量、价格和销售金额等信息,超市的经营者要查询“2020-12-10”和“2020-12-11”这两天收银金额超过 100 元的销售日期、收银员名称、销售数量和销售金额。
SELECT a.transdate,c.operatorname,d.goodsname,b.quantity,b.price,b.salesvalue
FROM demo.transactionhead AS a
JOIN demo.transactiondetails AS b
ON (a.transactionid = b.transactionid)
JOIN demo.operator AS c
ON (a.operatorid = c.operatorid)
JOIN demo.goodsmaster AS d
ON (b.itemnumber = d.itemnumber)
WHERE a.transdate IN ('2020-12-10','2020-12-11')
GROUP BY a.transdate,c.operatorname
HAVING SUM(b.salesvalue)>100;
我的试验
查询PASS_ALL 为Y,比部门代码来分组。
SELECT a.deptid,COUNT(b.MPLOYEE_ID)
FROM demo.season_people AS a
JOIN demo.season_passlist AS b
ON (a.emplid = b.MPLOYEE_ID)WHERE a.deptid IN ('MZH710','MZH720','MZH740') AND b.PASS_ALL IN ('Y')
GROUP BY a.deptid
HAVING COUNT(b.MPLOYEE_ID)=1;
08 | 聚合函数:怎么高效地进行分组统计?
聚合函数
- SUM()、AVG()、MAX()、MIN() 、 COUNT()、LEFT()、ORDER BY()
MySQL 中有 5 种聚合函数较为常用,分别是求和函数 SUM()、求平均函数 AVG()、最大值函数 MAX()、最小值函数 MIN() 和计数函数 COUNT()。
SELECT LEFT(a.transdate,10),c.goodsname,sum(b.quantity),sum(b.salesvalue)
FROM demo.transactionhead AS a
JOIN demo.transactiondetails AS b ON (a.transactionid = b.transactionid)
JOIN demo.goodsmaster AS c ON (b.itemnumber = c.itemnumber)
GROUP BY LEFT(a.transdate,10),c.goodsname
order BY LEFT(a.transdate,10),c.goodsname
LEFT
LEFT(str,n):表示返回字符串 str 最左边的 n 个字符。我们这里的 LEFT(a.transdate,10),表示返回交易时间字符串最左边的 10 个字符。在 MySQL 中,DATETIME 类型的默认格式是:YYYY-MM-DD,也就是说,年份 4 个字符,之后是“-”,然后是月份 2 个字符,之后又是“-”,然后是日 2 个字符,所以完整的年月日是 10 个字符。用户要求按照日期统计,所以,我们需要从日期时间数据中,把年月日的部分截取出来。
COUNT
要计算记录数,就要用到 COUNT() 函数了。这个函数有两种情况。COUNT(*):统计一共有多少条记录;COUNT(字段):统计有多少个不为空的字段值。
SELECT COUNT(*) FROM demo.operator
SELECT COUNT(operatorname) FROM demo.operator
思考题
如果用户想要查询一下,在商品信息表中,到底是哪种商品的商品名称有重复,分别重复了几次,该如何查询呢?
SELECT c.goodsname,COUNT(*)
FROM demo.transactionhead AS a
JOIN demo.transactiondetails AS b ON (a.transactionid = b.transactionid)
JOIN demo.goodsmaster AS c ON (b.itemnumber = c.itemnumber)
GROUP BY c.goodsname
HAVING COUNT(c.salesprice)>1
09 | 时间函数:时间类数据,MySQL是怎么处理的?
EXTRACT()
SELECT EXTRACT(hour FROM b.transdate) AS 时段,SUM(a.quantity),SUM(a.salesvalue)
FROM demo.transactiondetails AS a
JOIN demo.transactionhead AS b ON(a.transactionid = b.transactionid)
GROUP BY EXTRACT(HOUR FROM b.transdate)
ORDER BY EXTRACT(HOUR FROM b.transdate)
HOUR()
YEAR(date):获取 date 中的年。
MONTH(date):获取 date 中的月。
DAY(date):获取 date 中的日。
HOUR(date):获取 date 中的小时。
MINUTE(date):获取 date 中的分。
SECOND(date):获取 date 中的秒。
SELECT EXTRACT(hour FROM b.transdate) AS 时段,SUM(a.quantity),SUM(a.salesvalue)
FROM demo.transactiondetails AS a
JOIN demo.transactionhead AS b ON(a.transactionid = b.transactionid)
GROUP BY hour(b.transdate)
ORDER BY hour(b.transdate)
DATE_ADD() 和 LAST_DAY()
# 2019/12/10
#SELECT DATE_ADD('2020-12-10',INTERVAL - 1 YEAR);# 2019/11/10
#SELECT date_add(DATE_ADD('2020-12-10',INTERVAL - 1 YEAR),INTERVAL - 1 MONTH);# 2019/11/10
#SELECT last_day(date_add(DATE_ADD('2020-12-10',INTERVAL - 1 YEAR),INTERVAL - 1 MONTH));# 2019/12/01
#SELECT date_add(last_day(date_add(DATE_ADD('2020-12-10',INTERVAL - 1 YEAR),INTERVAL - 1 MONTH)),INTERVAL 1 DAY);# 2019/12/31
SELECT last_day(date_add(last_day(date_add(DATE_ADD('2020-12-10',INTERVAL - 1 YEAR),INTERVAL - 1 MONTH)),INTERVAL 1 DAY));
除了 DATE_ADD(),ADDDATE()、DATE_SUB() 和 SUBDATE() 也能达到同样的效果。ADDDATE():跟 DATE_ADD() 用法一致;DATE_SUB(),SUBDATE():与 DATE_ADD() 用法类似,方向相反,执行日期的减操作。
CURDATE()和 DAYOFWEEK(date)
CURDATE():获取当前的日期。日期格式为“YYYY-MM-DD”,也就是年月日的格式。DAYOFWEEK(date):获取日期“date”是周几。1 表示周日,2 表示周一,以此类推,直到 7 表示周六。
SELECT dayofweek(CURDATE())
DATE_FORMAT()
https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_date-format
SELECT DATE_FORMAT('2021-02-01 13:25:50',"%T")
SELECT DATE_FORMAT('2021-02-01 13:25:50',"%r")
DATEDIFF(date1,date2)
SELECT DATEDIFF('2021-02-01','2020-12-01')
CASE 函数(难)
CASE 表达式 WHEN 值1 THEN 表达式1 [ WHEN 值2 THEN 表达式2] ELSE 表达式m END
假设今天是 2021 年 02 月 06 日,通过下面的代码,我们就可以查到今天商品的全部折后价格了:
SELECT CURDATE() AS 日期,
case DAYOFWEEK(CURDATE())-1 when 0 then 7 else DAYOFWEEK(CURDATE())-1 end AS 周几,
a.goodsname AS 商品名称,
a.salesprice AS 价格,
IFNULL(b.discountrate,1) AS 折扣率,
a.salesprice*IFNULL(b.discountrate,1) AS 折后价格
FROM demo.goodsmaster AS a
left JOIN demo.discountrule AS b ON(a.itemnumber = b.itemnumber)
AND CASE DAYOFWEEK(CURDATE()) - 1 WHEN 0 THEN 7 ELSE DAYOFWEEK(CURDATE()) - 1 END = b.weekday;
IFNULL()
IFNULL(b.discountrate, 1)取不到值就默认为1
复习
10 | 如何进行数学计算、字符串处理和条件判断?
数学函数
向上取整 CEIL(X) 和 CEILING(X):返回大于等于 X 的最小 INT 型整数。
向下取整 FLOOR(X):返回小于等于 X 的最大 INT 型整数。
舍入函数 ROUND(X,D):X 表示要处理的数,D 表示保留的小数位数,处理的方式是四舍五入。ROUND(X) 表示保留 0 位小数。
积分的规则也很简单,就是消费一元积一分,不满一元不积分,那我们就需要对销售金额的数值进行取整。
首先,我们要通过关联查询,获得会员消费的相关信息:
SELECT c.membername AS '会员',
a.transactionid AS '单号',
b.transdate AS '交易时间',
d.goodsname AS '商品名称',
a.salesvalue AS '交易金额'
FROM demo.transactiondetails AS a
JOIN demo.transactionhead AS b ON (a.transactionid = b.transactionid)
JOIN demo.membermaster AS c ON (b.memberid = c.memberid)
JOIN demo.goodsmaster AS d ON (a.itemnumber = d.itemnumber)
FLOOR() , CEIL()
接着,我们用 FLOOR(a.salesvalue),对销售金额向下取整,获取会员积分值,代码如下:
SELECT c.membername AS '会员',
a.transactionid AS '单号',
b.transdate AS '交易时间',
d.goodsname AS '商品名称',
a.salesvalue AS '交易金额',
floor(a.salesvalue) AS '积分'
FROM demo.transactiondetails AS a
JOIN demo.transactionhead AS b ON (a.transactionid = b.transactionid)
JOIN demo.membermaster AS c ON (b.memberid = c.memberid)
JOIN demo.goodsmaster AS d ON (a.itemnumber = d.itemnumber)
如果用户的积分规则改为“不满一元积一分”,其实就是对金额数值向上取整,这个时候,我们就可以用 CEIL() 函数。操作方法和前面是一样的,我就不具体解释了。
ROUND()
如果要精确到角,可以设置保留 1 位小数:
SELECT ROUND(salesvalue,1)
FROM demo.transactiondetails
WHERE transactionid = 1
比如说,ROUND(X)是对 X 小数部分四舍五入,那么在“五入”的时候,返回的值是不是一定比 X 大呢?其实不一定,因为当 X 为负数时,五入的值会更小。
ABS() , MOD()
MySQL 还支持绝对值函数 ABS()和求余函数 MOD(),ABS(X)表示获取 X 的绝对值;MOD(X,Y)表示获取 X 被 Y 除后的余数。
字符串函数
CONCAT(s1,s2,…):表示把字符串 s1、s2……拼接起来,组成一个字符串。
CAST(表达式 AS CHAR):表示将表达式的值转换成字符串。
CHAR_LENGTH(字符串):表示获取字符串的长度。
SPACE(n):表示获取一个由 n 个空格组成的字符串。
SELECT
CONCAT(CAST(quantity AS CHAR),
SPACE(7 - CHAR_LENGTH(CAST(quantity AS CHAR)))) AS 数量
FROM demo.transactiondetails
WHERE transactionid = 1;
MySQL 还支持 SUBSTR()、MID()、TRIM()、LTRIM()、RTRIM()。
条件判断函数
IFNULL(V1,V2):表示如果 V1 的值不为空值,则返回 V1,否则返回 V2。
IF(表达式,V1,V2):如果表达式为真(TRUE),则返回 V1,否则返回 V2。
IFNULL
我们希望规格是空的商品,拼接商品信息字符串的时候,规格不要是空。这个问题,可以通过 IFNULL(specification, ‘’) 函数来解决。具体点说就是,对字段“specification”是否为空进行判断,如果为空,就返回空字符串,否则就返回商品规格 specification 的值。
SELECT goodsname,specification,
CONCAT(goodsname,'(',IFNULL(specification,''),')')
FROM demo.goodsmaster
IF
商品名称后面的那个空括号“()”会让客人觉得奇怪,能不能去掉呢?
SELECT goodsname,specification,
IF(ISNULL(specification),goodsname,CONCAT(goodsname,'(',specification,')'))
FROM demo.goodsmaster
总结
11 | 索引:怎么提高查询的速度?
单字段索引
如何创建单字段索引?
直接给数据表创建索引
CREATE INDEX 索引名 ON TABLE 表名 (字段);
CREATE INDEX index_trans ON demo.trans (transdate)SELECT quantity,price,transdate
FROM demo.trans
where transdate > '2023-12-11'
AND transdate < '2023-12-14'
创建表的同时创建索引
CREATE TABLE 表名
(
字段 数据类型,
….
{ INDEX | KEY } 索引名(字段)
)
修改表时创建索引
ALTER TABLE 表名 ADD { INDEX | KEY } 索引名 (字段);
EXPLAIN
EXPLAIN 关键字能够查看 SQL 语句的执行细节,包括表的加载顺序,表是如何连接的,以及索引使用情况等。
如何选择索引字段?
我建议你在选择索引字段的时候,要选择那些经常被用做筛选条件的字段。
组合索引
如果有多个索引,而这些索引的字段同时作为筛选字段出现在查询中的时候,MySQL 会选择使用最优的索引来执行查询操作。
如何创建组合索引?
跟创建单索引类似。
具体做法是,我们给销售流水表创建一个由 3 个字段 branchnumber、cashiernumber、itemnumber 组成的组合索引,如下所示:
CREATE INDEX Index_branchnumber_cashiernumber_itemnumber ON demo.trans (branchnumber,cashiernumber,itemnumber);
组合索引的原理
组合索引的多个字段是有序的,遵循左对齐的原则。比如我们创建的组合索引,排序的方式是 branchnumber、cashiernumber 和 itemnumber。因此,筛选的条件也要遵循从左向右的原则,如果中断,那么,断点后面的条件就没有办法利用索引了。
比如说我们刚才的条件,branchnumber = 11 AND cashiernumber = 1 AND itemnumber = 100,包含了从左到右的所有字段,所以可以最大限度使用全部组合索引。
假如把条件换成“cashiernumber = 1 AND itemnumber = 100”,由于我们的组合索引是按照 branchnumber、cashiernumber 和 itemnumber 的顺序建立的,最左边的字段 branchnumber 没有包含到条件当中,中断了,所以这个条件完全不能使用组合索引。
类似的,如果筛选的是一个范围,如果没有办法无法精确定位,也相当于中断。比如“branchnumber > 10 AND cashiernumber = 1 AND itemnumber = 100”这个条件,只能用到组合索引中 branchnumber>10 的部分,后面的索引就都用不上了。
删除索引
如果你要删除索引,就可以用:DROP INDEX 索引名 ON 表名;
当然, 有的索引不能用这种方法删除,比如主键索引,你就必须通过修改表来删除索引。语法如下:ALTER TABLE 表名 DROP PRIMARY KEY;
12 | 事务:怎么确保关联操作正确执行?
什么是事务?
带有ROLLBACK理论上就可以回退
START TRANSACTION 或者 BEGIN (开始事务)
一组DML语句
COMMIT(提交事务)
ROLLBACK(事务回滚)START TRANSACTION;
INSERT INTO demo.mytrans VALUES(1,1,'abc');
UPDATE demo.inventory SET invquantity = invquantity - 5 ;
COMMIT;
rollback;
START TRANSACTION 和 BEGIN:表示开始事务,意思是通知 MySQL,后面的 DML 操作都是当前事务的一部分。
COMMIT:表示提交事务,意思是执行当前事务的全部操作,让数据更改永久有效。
ROLLBACK:表示回滚当前事务的操作,取消对数据的更改。
事务有 4 个主要特征
原子性:表示事务中的操作要么全部执行,要么全部不执行,像一个整体,不能从中间打断。
一致性:表示数据的完整性不会因为事务的执行而受到破坏。
隔离性:表示多个事务同时执行的时候,不互相干扰。不同的隔离级别,相互独立的程度不同。
持久性:表示事务对数据的修改是永久有效的,不会因为系统故障而失效。
原子性(需加强学习)
在这个存储过程中,我使用了“DECLARE EXIT HANDLER FOR SQLEXCEPTION ROLLBACK;”这个语句,来监控 SQL 语句的执行结果,一旦发发生错误,就自动回滚并退出。通过这个机制,我们就实现了对事务中的 SQL 操作进行监控,如果发现事务中的任何 SQL 操作发生错误,就自动回滚。
#DELIMITER ;
#CREATE PROCEDURE demo.test()
#BEGINDECLARE EXIT HANDLER FOR SQLEXCEPTION ROLLBACK;
START TRANSACTION;
INSERT INTO demo.mytrans VALUES(1,1,5);
UPDATE demo.inventory SET invquantity = invquantity - 5 WHERE itemnumber = 1;
COMMIT;
end
我们可以通过 MySQL 的函数 ROW_COUNT() 的返回,来判断一个 DML 操作是否失败,-1 表示操作失败,否则就表示影响的记录数。
如何用好事务的隔离性?
MySQL 支持 4 种事务隔离等级。
READ UNCOMMITTED:可以读取事务中还未提交的被更改的数据。
READ COMMITTED:只能读取事务中已经提交的被更改的数据。
REPEATABLE READ:表示一个事务中,对一个数据读取的值,永远跟第一次读取的值一致,不受其他事务中数据操作的影响。这也是 MySQL 的默认选项。
SERIALIZABLE:表示任何一个事务,一旦对某一个数据进行了任何操作,那么,一直到这个事务结束,MySQL 都会把这个数据锁住,禁止其他事务对这个数据进行任何操作。
一般来讲,使用 MySQL 默认的隔离等级 REPEATABLE READ,就已经够了。不过,也不排除需要对一些关键的数据操作,使用最高的隔离等级 SERIALIZABLE。
13 | 临时表:复杂查询,如何保存中间结果?
临时表是什么?
临时表是一种特殊的表,用来存储查询的中间结果,并且会随着当前连接的结束而自动删除。
MySQL 中有 2 种临时表,分别是内部临时表和外部临时表:内部临时表主要用于性能优化,由系统自动产生,我们无法看到;外部临时表通过 SQL 语句创建,我们可以使用。
CREATE TEMPORARY TABLE 表名
(
字段名 字段类型,
...
);
跟普通表相比,临时表有 3 个不同的特征:临时表的创建语法需要用到关键字 TEMPORARY;临时表创建完成之后,只有当前连接可见,其他连接是看不到的,具有连接隔离性;临时表在当前连接结束之后,会被自动删除。
如何用临时表简化复杂查询?
1.查询出每个单品的销售数量和销售金额,并存入临时表:
CREATE TEMPORARY TABLE demo.mysales
SELECT itemnumber,
SUM(quantity) AS QUANTITY,
SUM(salesvalue) AS salesvalue
FROM demo.transactiondetails
GROUP BY itemnumber;SELECT * FROM demo.mysales;
2.SQL 语句计算进货数据,并且保存在临时表里面:
CREATE TEMPORARY TABLE demo.myimport
SELECT b.itemnumber,SUM(b.quantity) AS quantity,SUM(b.importvalue) AS importvalue
FROM demo.importhead AS a JOIN demo.importdetails AS b ON (a.listnumber = b.listnumber)
GROUP BY b.itemnumber;SELECT * FROM demo.myimport;
3.下面的 SQL 语句计算返厂信息,并且保存到临时表中。
CREATE TEMPORARY TABLE demo.myreturn
SELECT b.itemnumber,SUM(b.quantity) AS quantity,SUM(b.importvalue) AS importvalue
FROM demo.returnhead AS a JOIN demo.returndetails AS b ON (a.listnumber = b.listnumber)
GROUP BY b.itemnumber;SELECT * FROM demo.myreturn;
4.把单品的销售信息、进货信息和返厂信息汇总到一起了。
CREATE TEMPORARY TABLE demo.mysales
SELECT itemnumber,
SUM(quantity) AS QUANTITY,
SUM(salesvalue) AS salesvalue
FROM demo.transactiondetails
GROUP BY itemnumber;CREATE TEMPORARY TABLE demo.myimport
SELECT b.itemnumber,SUM(b.quantity) AS quantity,SUM(b.importvalue) AS importvalue
FROM demo.importhead AS a JOIN demo.importdetails AS b ON (a.listnumber = b.listnumber)
GROUP BY b.itemnumber;CREATE TEMPORARY TABLE demo.myreturn
SELECT b.itemnumber,SUM(b.quantity) AS quantity,SUM(b.importvalue) AS importvalue
FROM demo.returnhead AS a JOIN demo.returndetails AS b ON (a.listnumber = b.listnumber)
GROUP BY b.itemnumber;SELECT
a.itemnumber,
a.goodsname,
ifnull(b.quantity,0) as salesquantity, -- 如果没有销售记录,销售数量设置为0
ifnull(c.quantity,0) as importquantity, -- 如果没有进货,进货数量设为0
ifnull(d.quantity,0) as returnquantity -- 如果没有返厂,返厂数量设为0
FROM demo.goodsmaster a -- 商品信息表放在左边进行左连接,确保所有的商品都包含在结果集中
LEFT JOIN demo.mysales b ON (a.itemnumber=b.itemnumber)
LEFT JOIN demo.myimport c ON (a.itemnumber=c.itemnumber)
LEFT JOIN demo.myreturn d ON (a.itemnumber=d.itemnumber)
HAVING salesquantity>0 OR importquantity>0 OR returnquantity>0; -- 在结果集中剔除没有销售,没有进货,也没有返厂的商品
内存临时表和磁盘临时表
创建一个内存中的临时表:
CREATE TEMPORARY TABLE demo.mysales
ENGINE = MEMORY
SELECT itemnumber,
SUM(quantity) AS QUANTITY,
SUM(salesvalue) AS salesvalue
FROM demo.transactiondetails
GROUP BY itemnumber;
在磁盘上创建临时表(默认)
速度比较
我们向刚刚的两张表里都插入同样数量的记录,然后再分别做一个查询:
14 | 视图:如何简化查询?
视图的创建及其好处
视图的创建
CREATE VIEW demo.trans_goodmaster AS
SELECT a.transdate,a.itemnumber,b.goodsname,SUM(a.salesquantity) AS quantity,SUM(a.salesvalue) AS salesvalue
FROM demo.trans AS a
JOIN demo.goodsmaster AS b ON (a.itemnumber = b.itemnumber)
GROUP BY a.transdate,a.itemnumber;
视图与其他表联合查询
SELECT a.transdate,a.itemnumber,a.goodsname,a.quantity,b.invquantity
FROM demo.trans_goodmaster AS a
JOIN demo.inventoryhist AS b ON (a.transdate = b.invdate and a.itemnumber = b.itemnumber)
如何操作视图?
如何操作视图中的数据?
1. 在视图中插入数据
只有视图中的字段跟实际数据表中的字段完全一样,MySQL 才允许通过视图插入数据。
insert into demo.trans_goodsmaster
VALUES(5,'0005','测试',100)
2. 删除视图中的数据
DELETE from demo.trans_goodsmaster
WHERE itemnumber = 5
3. 修改视图中的数据
update demo.trans_goodsmaster
SET salesprice = 100.11
WHERE itemnumber = 1
视图的优点
15 | 存储过程:如何提高程序的性能和安全性?
如何创建存储过程?
CREATE PROCEDURE 存储过程名 ([ IN | OUT | INOUT] 参数名称 类型)程序体
DELIMITER // -- 设置分割符为//
CREATE PROCEDURE demo.dailyoperation(transdate TEXT)
BEGIN -- 开始程序体
DECLARE startdate,enddate DATETIME; -- 定义变量
SET startdate = date_format(transdate,'%Y-%m-%d'); -- 给起始时间赋值
SET enddate = date_add(startdate,INTERVAL 1 DAY); -- 截止时间赋值为1天以后
-- 删除原有数据
DELETE FROM demo.dailystatistics
WHERE
salesdate = startdate;
-- 插入新计算的数据
INSERT into dailystatistics
(
salesdate,
itemnumber,
quantity,
actualvalue,
cost,
profit,
profitratio
)
SELECT
LEFT(b.transdate,10),
a.itemnumber,
SUM(a.quantity), -- 数量总计
SUM(a.salesvalue), -- 金额总计
SUM(a.quantity*c.avgimportprice), -- 计算成本
SUM(a.salesvalue-a.quantity*c.avgimportprice), -- 计算毛利
CASE sum(a.salesvalue) WHEN 0 THEN 0
ELSE round(sum(a.salesvalue-a.quantity*c.avgimportprice)/sum(a.salesvalue),4) END -- 计算毛利率
FROM
demo.transactiondetails AS a
JOIN
demo.transactionhead AS b
ON (a.transactionid = b.transactionid)
JOIN
demo.goodsmaster AS c
ON (a.itemnumber=c.itemnumber)
WHERE
b.transdate>startdate AND b.transdate<enddate
GROUP BY
LEFT(b.transdate,10),a.itemnumber
ORDER BY
LEFT(b.transdate,10),a.itemnumber;
END
//
DELIMITER ; -- 恢复分隔符为;
存储过程的参数定义(难)
参数有 3 种,分别是 IN、OUT 和 INOUT。
IN 表示输入的参数,存储过程只是读取这个参数的值。如果没有定义参数种类,默认就是 IN,表示输入参数。
OUT 表示输出的参数,存储过程在执行的过程中,把某个计算结果值赋给这个参数,执行完成之后,调用这个存储过程的客户端或者应用程序就可以读取这个参数返回的值了。
INOUT 表示这个参数既可以作为输入参数,又可以作为输出参数使用。
如何查看存储过程?
SHOW CREATE PROCEDURE demo.dailyoperation;
如何调用存储过程?
CALL demo.dailyoperation('2020-12-01');
如何修改和删除存储过程?
删除存储过程
DROP PROCEDURE 存储过程名称;
思考题
请写一个简单的存储过程,要求是定义 2 个参数,一个输入参数 a,数据类型是 INT;另一个输出参数是 b,类型是 INT。程序体完成的操作是:b = a + 1。
1.定义存储过程
DELIMITER //
CREATE PROCEDURE demo.test(IN a INT,OUT b INT)
BEGINSET b = a + 1;
END
//
DELIMITER ;
2.调用存储过程
CALL demo.test(100,@b);
3.查看导出参数
SELECT @b
参数报错参考链接https://blog.csdn.net/qq_41490938/article/details/115585853
16 | 游标:对于数据集中的记录,该怎么逐条处理?(难)
游标
存储过程中使用游标的 4 个步骤,分别是定义游标、打开游标、读取游标数据和关闭游标。
DECLARE 游标名 CURSOR FOR 查询语句OPEN 游标名称;FETCH 游标名 INTO 变量列表;CLOSE 游标名;
与游标结合使用的流程控制语句
与游标结合使用的流程控制语句,包括循环语句 LOOP、WHILE 和 REPEAT;条件判断语句 IF 和 CASE;还有跳转语句 LEAVE 和 ITERATE。
条件处理语句
DECLARE 处理方式 HANDLER FOR 问题 操作;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
流程控制语句-跳转语句
ITERATE 语句:只能用在循环语句内,表示重新开始循环。
LEAVE 语句:可以用在循环语句内,或者以 BEGIN 和 END 包裹起来的程序体内,表示跳出循环或者跳出程序体的操作。
流程控制语句-循环语句
流程控制语句-条件判断语句
案例
要验收进货单,我们就需要对每一个进货商品进行两个操作:在现有库存数量的基础上,加上本次进货的数量;根据本次进货的价格、数量,现有商品的平均进价和库存,计算新的平均进价:(本次进货价格 * 本次进货数量 + 现有商品平均进价 * 现有商品库存)/(本次进货数量 + 现有库存数量)。
mysql> DELIMITER //
mysql> CREATE PROCEDURE demo.mytest(mylistnumber INT)
-> BEGIN
-> DECLARE mystockid INT;
-> DECLARE myitemnumber INT;
-> DECLARE myquantity DECIMAL(10,3);
-> DECLARE myprice DECIMAL(10,2);
-> DECLARE done INT DEFAULT FALSE; -- 用来控制循环结束
-> DECLARE cursor_importdata CURSOR FOR -- 定义游标
-> SELECT b.stockid,a.itemnumber,a.quantity,a.importprice
-> FROM demo.importdetails AS a
-> JOIN demo.importhead AS b
-> ON (a.listnumber=b.listnumber)
-> WHERE a.listnumber = mylistnumber;
-> DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE; -- 条件处理语句
->
-> OPEN cursor_importdata; -- 打开游标
-> FETCH cursor_importdata INTO mystockid,myitemnumber,myquantity,myprice; -- 读入第一条记录
-> REPEAT
-> -- 更新进价
-> UPDATE demo.goodsmaster AS a,demo.inventory AS b
-> SET a.avgimportprice = (a.avgimportprice*b.invquantity+myprice*myquantity)/(b.invquantity+myquantity)
-> WHERE a.itemnumber=b.itemnumber AND b.stockid=mystockid AND a.itemnumber=myitemnumber;
-> -- 更新库存
-> UPDATE demo.inventory
-> SET invquantity = invquantity + myquantity
-> WHERE stockid = mystockid AND itemnumber=myitemnumber;
-> -- 获取下一条记录
-> FETCH cursor_importdata INTO mystockid,myitemnumber,myquantity,myprice;
-> UNTIL done END REPEAT;
-> CLOSE cursor_importdata;
-> END
-> //
Query OK, 0 rows affected (0.02 sec)
-> DELIMITER ;
把 MySQL 的分隔符改成“//”。开始程序体之后,我定义了 4 个变量,分别是 mystockid、myitemnumber、myquantity 和 myprice,这几个变量的作用是,存储游标中读取的仓库编号、商品编号、进货数量和进货价格数据。定义游标。这里我指定了游标的名称,以及游标可以处理的数据集(mylistnumber 指定的进货单的全部进货商品明细数据)。定义条件处理语句“DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;”。打开游标,读入第一条记录,然后开始执行数据操作。关闭游标,结束程序。
思考题
你能自己写一个简单的存储过程,用游标来逐一处理一个数据表中的数据吗?要求:编号为偶数的记录,myquant=myquant+1;编号是奇数的记录,myquant=myquant+2。
DELIMITER //
CREATE PROCEDURE demo.myproc()
BEGINDECLARE myid INT;DECLARE myq INT;DECLARE done INT DEFAULT FALSE;DECLARE cursor_test CURSOR FOR SELECT * FROM demo.test;DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;OPEN cursor_test;FETCH cursor_test INTO myid,myq;REPEATIF (myid MOD 2 = 0) THEN -- 如果是偶数,加1UPDATE demo.test SET myquant = myquant + 1 WHERE id = myid;ELSE -- 奇数加2UPDATE demo.test SET myquant = myquant + 2 WHERE id = myid;END IF;FETCH cursor_test INTO myid,myq;UNTIL done END REPEAT;CLOSE cursor_test;
END
//
DELIMITER ;
17 | 触发器:如何让数据修改自动触发关联操作,确保数据一致性?
触发器的优缺点
首先,触发器可以确保数据的完整性。
其次,触发器可以帮助我们记录操作日志。
另外,触发器还可以用在操作数据前,对数据进行合法性检查。
触发器最大的一个问题就是可读性差。ERROR 1054 (42S22): Unknown column 'aa' in 'field list'
如何操作触发器
创建触发器的语法结构是
CREATE TRIGGER 触发器名称 {BEFORE|AFTER} {INSERT|UPDATE|DELETE}
ON 表名 FOR EACH ROW 表达式;查看触发器的语句是:
SHOW TRIGGERS\G;删除触发器的语法结构是:
DROP TRIGGER 触发器名称;
案例
会员信息表(demo.membermaster)
会员储值历史表(demo.deposithist)
定义trigger
DELIMITER //
CREATE TRIGGER demo.upd_membermaster BEFORE UPDATE -- 在更新前触发
ON demo.membermaster
FOR EACH ROW -- 表示每更新一条记录,触发一次
BEGIN -- 开始程序体
IF (new.memberdeposit <> old.memberdeposit) -- 如果储值金额有变化
THEN
INSERT INTO demo.deposithist
(
memberid,
transdate,
oldvalue,
newvalue,
changedvalue
)
SELECT
NEW.memberid,
NOW(),
OLD.memberdeposit, -- 更新前的储值金额
NEW.memberdeposit, -- 更新后的储值金额
NEW.memberdeposit-OLD.memberdeposit; -- 储值金额变化值
END IF;
END
//
DELIMITER ;
触发trigger
UPDATE demo.membermaster
SET memberdeposit = memberdeposit + 10
WHERE memberid = 1
18 | 权限管理:如何控制数据库访问,消除安全隐患?
1.操作权限
创建角色
CREATE ROLE 角色名;CREATE ROLE 'manager'@'localhost';不写主机名 默认是通配符% 可以从任何主机登录
角色授权
GRANT 权限 ON 表名 TO 角色名;GRANT SELECT,INSERT,DELETE,UPDATE ON demo.user TO 'manager';
查看角色权限
SHOW GRANTS FOR 'manager';
删除角色
DROP ROLE 角色名称;
2.操作用户
创建用户
CREATE USER 用户名 [IDENTIFIED BY 密码];create user bb identified by 123;
给用户授权
直接授权GRANT 角色名称 TO 用户名称;通过角色授权GRANT 权限 ON 表名 TO 用户名;
查看用户权限
SHOW GRANTS FOR 用户名;
删除用户
DROP USER 用户名;
3.注意点
mysql创建角色后 默认是没有激活的,需要激活(目前无法激活用户)。mysql8开始才支持角色
SET global activate_all_roles_on_login=ON;
但是可能面临激活失败,就可以直接将table授权给用户,而不通过角色。
直接将table授权给用户,而不通过角色
可以直接将table授权给用户,而不通过角色
GRANT SELECT,INSERT,DELETE,UPDATE ON demo.membermaster TO ‘season’;
19 | 日志(上):系统出现问题,如何及时发现?
通用查询日志
1.开启通用查询日志
SET GLOBAL general_log = 'ON';
SET @@global.general_log_file = 'H:\mytest.log';
2.查看通用查询日志
去H:\mytest.log这里查看
3.删除通用查询日志
ET GLOBAL general_log = 'OFF';
慢查询日志
慢查询日志用来记录执行时间超过指定时长的查询。
1.MySQL 的配置文件“my.ini”
slow-query-log=1 -- 表示开启慢查询日志,系统将会对慢查询进行记录。slow_query_log_file="GJTECH-PC-slow.log" -- 表示慢查询日志的名称是"GJTECH-PC-slow.log"。这里没有指定文件夹,默认就是数据目录:"C:\ProgramData\MySQL\MySQL Server 8.0\Data"。long_query_time=10 -- 表示慢查询的标准是查询执行时间超过10秒
错误日志
错误日志记录了 MySQL 服务器启动、停止运行的时间,以及系统启动、运行和停止过程中的诊断信息,包括错误、警告和提示等。
# Error Logging.
log-error="GJTECH-PC.err"
InnoDB: using atomic writes.
2023-09-01 8:42:13 0 [Note] InnoDB: Mutexes and rw_locks use Windows interlocked functions
2023-09-01 8:42:13 0 [Note] InnoDB: Uses event mutexes
2023-09-01 8:42:13 0 [Note] InnoDB: Compressed tables use zlib 1.2.11
2023-09-01 8:42:13 0 [Note] InnoDB: Number of pools: 1
2023-09-01 8:42:13 0 [Note] InnoDB: Using SSE2 crc32 instructions
2023-09-01 8:42:13 0 [Note] InnoDB: Initializing buffer pool, total size = 1073741824, chunk size = 134217728
2023-09-01 8:42:13 0 [Note] InnoDB: Completed initialization of buffer pool
2023-09-01 8:42:13 0 [Note] InnoDB: 128 rollback segments are active.
2023-09-01 8:42:13 0 [Note] InnoDB: Creating shared tablespace for temporary tables
2023-09-01 8:42:13 0 [Note] InnoDB: Setting file '.\ibtmp1' size to 12 MB. Physically writing the file full; Please wait ...
2023-09-01 8:42:13 0 [Note] InnoDB: File '.\ibtmp1' size is now 12 MB.
2023-09-01 8:42:13 0 [Note] InnoDB: 10.5.1 started; log sequence number 60142; transaction id 21
2023-09-01 8:42:13 0 [Note] Plugin 'FEEDBACK' is disabled.
2023-09-01 8:42:13 0 [Note] InnoDB: Loading buffer pool(s) from C:\Program Files\MariaDB 10.5\data\ib_buffer_pool
2023-09-01 8:42:13 0 [Note] InnoDB: Buffer pool(s) load completed at 230901 8:42:13
2023-09-01 8:42:13 0 [Note] Server socket created on IP: '::'.
2023-09-01 8:42:13 0 [Note] Reading of all Master_info entries succeeded
2023-09-01 8:42:13 0 [Note] Added new Master_info '' to hash table
2023-09-01 8:42:13 0 [Note] C:\Program Files\MariaDB 10.5\bin\mysqld.exe: ready for connections.
Version: '10.5.1-MariaDB' socket: '' port: 3306 mariadb.org binary distribution
2023-09-01 8:49:49 4 [Warning] Access denied for user 'root'@'localhost' (using password: NO)
2023-09-01 10:27:06 9 [Warning] Aborted connection 9 to db: 'demo' user: 'root' host: 'localhost' (Got an error reading communication packets)
2023-09-01 10:35:10 10 [Warning] Aborted connection 10 to db: 'demo' user: 'root' host: 'localhost' (Got an error reading communication packets)
2023-09-01 11:19:31 11 [Warning] Aborted connection 11 to db: 'demo' user: 'root' host: 'localhost' (Got an error reading communication packets)
2023-09-01 14:45:46 33 [Warning] Access denied for user 'season'@'localhost' (using password: YES)
2023-09-01 15:13:45 36 [ERROR] Could not use C:Users13073219Desktopseasonmytest.log for logging (error 22). Turning logging off for the whole duration of the MariaDB server process. To turn it on again: fix the cause, shutdown the MariaDB server and restart it.
2023-09-01 15:13:56 36 [ERROR] Could not use C:Users13073219Desktopseasonmytest.log for logging (error 22). Turning logging off for the whole duration of the MariaDB server process. To turn it on again: fix the cause, shutdown the MariaDB server and restart it.
20 | 日志(下):系统故障,如何恢复数据?
相关文章:

【极客时间】MySQL 必知必会-20230901
03 | 表:怎么创建和修改数据表? 新增数据表 CREATE DATABASE demo;CREATE TABLE goodsmaster (barcode TEXT,goodsname TEXT,price DOUBLE, itemnumber INT PRIMARY KEY AUTO_INCREMENT);INSERT INTO demo.goodsmaster (barcode, goodsname,price) VAL…...

53 个 CSS 特效 3(完)
53 个 CSS 特效 3(完) 前两篇地址: 53 个 CSS 特效 153 个 CSS 特效 2 这里是第 33 到 53 个,很多内容都挺重复的,所以这里解释没之前的细,如果漏了一些之前的笔记会补一下,写过的就会跳过。…...

简单数学题:找出最大的可达成数字
来看一道简单的数学题:力扣2769. 找出最大的可达成数字 题目描述的花里胡哨,天花乱坠,但这道题目非常简单。我们最多执行t次操作,只需每次操作都让x-1,让num1,执行t次操作后,x就变为xtÿ…...

[C++ 网络协议] 套接字的多种可选项
目录 1. 套接字的可选项 2. 获取/设置套接字可选项 2.1 getsockopt函数(获取套接字可选项) 2.2 setsockopt函数(设置套接字可选项) 3. 常用套接字可选项 3.1 SOL_SOCKET协议层的SO_TYPE可选项 3.2 SOL_SOCKET协议层的SO_SN…...

2022年03月 C/C++(五级)真题解析#中国电子学会#全国青少年软件编程等级考试
第1题:数字变换 给定一个包含 5 个数字(0-9)的字符串, 例如 “02943”, 请将“12345”变换到它。 你可以采取 3 种操作进行变换 (1)交换相邻的两个数字 (2)将一个数字加 1。 如果加 1 后大于 9, 则变为 0 (3)将一个数字加倍。 如果加倍后大于 9,则将其变为加倍后的…...
***数据转换中常用的两个函数 sscanf,sprintf
1、sscanf将字符串转换成想要的整数或浮点数 (HMI屏中输入浮点数据,到mcu后要转换成对应的浮点数据) sscanf(“0.9”,“%f”,getData) /*! \brief 文本控件通知 \details 当文本通过键盘更新(或调用GetControlValue)时,执行此函数 \details 文本控件的内容以字符串形…...
软件工程(十九) 软件测试
软件测试主要了解软件测试的方法和软件的调试。 1、软件测试方法 1.1、测试基本思想 尽早、不断的进行测试 在V模型其实已经凸显出这种思想了程序员避免测试自己设计的程序 因为测试自己设计的程序,其实是不容易发现问题的,因为人从本质上都不愿意找自己的茬。而且由于你的…...
go中读写锁(rwmutex)源码解读实现原理
go读写锁的实现原理 1、RWMutex读写锁的概念 读写锁也就是我们所使用的RWMutex,其实是对于go本身的mutex做的一个拓展,当一个goroutine获得了读锁后,其他goroutine同样可以获得读锁,但是不能获得写锁。相反,当一个go…...

【人工智能】—_深度优先搜索、代价一致搜索、深度有限搜索、迭代深度优先搜索、图搜索
【人工智能】无信息搜索—BFS 、代价一致、DFS、深度受限、迭代深入深度优先、图搜索 什么是搜索 搜索问题是指既不能通过数学建模解决,又没有其他算法可以套用或者非遍历所有情况才能得出正确结果。这时就需要采用搜索算法来解决问题。搜索就是一种通过穷举所有解…...

uni-app 客服按钮可上下拖动动
项目需求: 因为悬浮客服有时候会遮挡住界面内容,故需要对悬浮的气泡弹窗做可拖动操作 movable-area:可拖动区域 movable-view:可移动的视图容器,在页面中可以拖拽滑动或双指缩放。 属性说明 属性名类型默认值说…...

基于Android的旅游管理系统 微信小程序
随着网络科技的发展,移动智能终端逐渐走进人们的视线,相关应用越来越广泛,并在人们的日常生活中扮演着越来越重要的角色。因此,关键应用程序的开发成为影响移动智能终端普及的重要因素,设计并开发实用、方便的应用程序…...

python-数据可视化-下载数据-CSV文件格式
数据以两种常见格式存储:CSV和JSON CSV文件格式 comma-separated values import csv filename sitka_weather_07-2018_simple.csv with open(filename) as f:reader csv.reader(f)header_row next(reader)print(header_row) # [USW00025333, SITKA AIRPORT, A…...

时序预测 | MATLAB实现SSA-XGBoost(麻雀算法优化极限梯度提升树)时间序列预测
时序预测 | MATLAB实现SSA-XGBoost(麻雀算法优化极限梯度提升树)时间序列预测 目录 时序预测 | MATLAB实现SSA-XGBoost(麻雀算法优化极限梯度提升树)时间序列预测预测效果基本介绍模型描述程序设计参考资料 预测效果 基本介绍 Matlab实现SSA-XGBoost时间序列预测,麻…...
leetcode 823 带因子的二叉树
用动态规划 如果两个节点值不同,要乘2,因为两个节点可以互换位置 dp[i] dp[left] * dp[right] * 2 如果相同 dp[i] dp[left] * dp[right] class Solution {public int numFactoredBinaryTrees(int[] arr) {Arrays.sort(arr);int n arr.length;long[] dp ne…...

钉钉消息已读、未读咋实现的嘞?
前言 一款app,消息页面有:钱包通知、最近访客等各种通知类别,每个类别可能有新的通知消息,实现已读、未读功能,包括多少个未读,这个是怎么实现的呢?比如用户A访问了用户B的主页,难道…...

Java 读取TIFF JPEG GIF PNG PDF
Java 读取TIFF JPEG GIF PNG PDF 本文解决方法基于开源 tesseract 下载适合自己系统版本的tesseract ,官网链接:https://digi.bib.uni-mannheim.de/tesseract/ 2. 下载之后安装,安装的时候选择选择语言包,我选择了中文和英文 3.…...

研磨设计模式day14模板方法模式
目录 场景 原有逻辑 有何问题 解决方案 解决思路 代码实现 重写示例 模板方法的优缺点 模板方法的本质 何时选用 场景 现在模拟一个场景,两个人要登录一个系统,一个是管理员一个是用户,这两个不同身份的登录是由后端对应的两个接…...

7 集群基本测试
1. 上传小文件到集群 在hadoop路径下执行命令创建一个文件夹用于存放即将上传的文件: [atguiguhadoop102 ~]$ hadoop fs -mkdir /input上传: [atguiguhadoop102 hadoop-3.1.3]$ hadoop fs -put wcinput/work.txt /input2.上传大文件 [atguiguhadoop1…...

chrono学习(一)
我想用chrono进行沙土的仿真,首先学习demo_GPU_ballCosim.cpp,这个例子仿真了一些沙土的沉降过程。 首先,运行编辑完成的文件demo_GPU_ballCosim: (base) eowyneowyn-MS-7D20:~/build_chrono/bin$ ./demo_GPU_ballCosim 运行完得…...
后端面试话术集锦第 十 篇:springMVC面试话术
这是后端面试集锦第十篇博文——springMVC面试话术❗❗❗ 1. 介绍一下springMVC springmvc是一个视图层框架,通过MVC模型让我们很方便的接收和处理请求和响应。 我给你说说他里边的几个核心组件吧: 它的核心控制器是DispatcherServlet,他的作用是接收用户请求,然后给用户…...

springboot 百货中心供应链管理系统小程序
一、前言 随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱,百货中心供应链管理系统被用户普遍使用,为方…...
React hook之useRef
React useRef 详解 useRef 是 React 提供的一个 Hook,用于在函数组件中创建可变的引用对象。它在 React 开发中有多种重要用途,下面我将全面详细地介绍它的特性和用法。 基本概念 1. 创建 ref const refContainer useRef(initialValue);initialValu…...
连锁超市冷库节能解决方案:如何实现超市降本增效
在连锁超市冷库运营中,高能耗、设备损耗快、人工管理低效等问题长期困扰企业。御控冷库节能解决方案通过智能控制化霜、按需化霜、实时监控、故障诊断、自动预警、远程控制开关六大核心技术,实现年省电费15%-60%,且不改动原有装备、安装快捷、…...

DBAPI如何优雅的获取单条数据
API如何优雅的获取单条数据 案例一 对于查询类API,查询的是单条数据,比如根据主键ID查询用户信息,sql如下: select id, name, age from user where id #{id}API默认返回的数据格式是多条的,如下: {&qu…...

20个超级好用的 CSS 动画库
分享 20 个最佳 CSS 动画库。 它们中的大多数将生成纯 CSS 代码,而不需要任何外部库。 1.Animate.css 一个开箱即用型的跨浏览器动画库,可供你在项目中使用。 2.Magic Animations CSS3 一组简单的动画,可以包含在你的网页或应用项目中。 3.An…...
现有的 Redis 分布式锁库(如 Redisson)提供了哪些便利?
现有的 Redis 分布式锁库(如 Redisson)相比于开发者自己基于 Redis 命令(如 SETNX, EXPIRE, DEL)手动实现分布式锁,提供了巨大的便利性和健壮性。主要体现在以下几个方面: 原子性保证 (Atomicity)ÿ…...

打手机检测算法AI智能分析网关V4守护公共/工业/医疗等多场景安全应用
一、方案背景 在现代生产与生活场景中,如工厂高危作业区、医院手术室、公共场景等,人员违规打手机的行为潜藏着巨大风险。传统依靠人工巡查的监管方式,存在效率低、覆盖面不足、判断主观性强等问题,难以满足对人员打手机行为精…...
作为测试我们应该关注redis哪些方面
1、功能测试 数据结构操作:验证字符串、列表、哈希、集合和有序的基本操作是否正确 持久化:测试aof和aof持久化机制,确保数据在开启后正确恢复。 事务:检查事务的原子性和回滚机制。 发布订阅:确保消息正确传递。 2、性…...

AxureRP-Pro-Beta-Setup_114413.exe (6.0.0.2887)
Name:3ddown Serial:FiCGEezgdGoYILo8U/2MFyCWj0jZoJc/sziRRj2/ENvtEq7w1RH97k5MWctqVHA 注册用户名:Axure 序列号:8t3Yk/zu4cX601/seX6wBZgYRVj/lkC2PICCdO4sFKCCLx8mcCnccoylVb40lP...

02.运算符
目录 什么是运算符 算术运算符 1.基本四则运算符 2.增量运算符 3.自增/自减运算符 关系运算符 逻辑运算符 &&:逻辑与 ||:逻辑或 !:逻辑非 短路求值 位运算符 按位与&: 按位或 | 按位取反~ …...