mysql的高级进阶

之前我们学了mysql的查询与高级查询和存储过程今天我们来学习mysql的高级进阶

mysql的进阶操作就是多个表进行互相关联的查询操作,首先准备多个数据表。

建多个表

DROP TABLE IF EXISTS `class`;
CREATE TABLE `class` (
  `cid` int(11) NOT NULL AUTO_INCREMENT,
  `caption` varchar(32) NOT NULL,
  PRIMARY KEY (`cid`)
) ENGINE=innoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;

# innoDB 有外键约束   myisam 注释的作用
DROP TABLE IF EXISTS `course`;
CREATE TABLE `course` (
  `cid` int(11) NOT NULL AUTO_INCREMENT,
  `cname` varchar(32) NOT NULL,
  `teacher_id` int(11) NOT NULL,
  PRIMARY KEY (`cid`),
  KEY `fk_course_teacher` (`teacher_id`),
  CONSTRAINT `fk_course_teacher` FOREIGN KEY (`teacher_id`) REFERENCES `teacher` (`tid`)
) ENGINE=innoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;

DROP TABLE IF EXISTS `score`;
CREATE TABLE `score` (
  `sid` int(11) NOT NULL AUTO_INCREMENT,
  `student_id` int(11) NOT NULL,
  `course_id` int(11) NOT NULL,
  `num` int(11) NOT NULL,
  PRIMARY KEY (`sid`),
  KEY `fk_score_student` (`student_id`),
  KEY `fk_score_course` (`course_id`),
  CONSTRAINT `fk_score_course` FOREIGN KEY (`course_id`) REFERENCES `course` (`cid`),
  CONSTRAINT `fk_score_student` FOREIGN KEY (`student_id`) REFERENCES `student` (`sid`)
) ENGINE=innoDB AUTO_INCREMENT=53 DEFAULT CHARSET=utf8;

DROP TABLE IF EXISTS `student`;
CREATE TABLE `student` (
  `sid` int(11) NOT NULL AUTO_INCREMENT,
  `gender` char(1) NOT NULL,
  `class_id` int(11) NOT NULL,
  `sname` varchar(32) NOT NULL,
  PRIMARY KEY (`sid`),
  KEY `fk_class` (`class_id`),
  CONSTRAINT `fk_class` FOREIGN KEY (`class_id`) REFERENCES `class` (`cid`)
) ENGINE=innoDB AUTO_INCREMENT=17 DEFAULT CHARSET=utf8;

DROP TABLE IF EXISTS `teacher`;
CREATE TABLE `teacher` (
  `tid` int(11) NOT NULL AUTO_INCREMENT,
  `tname` varchar(32) NOT NULL,
  PRIMARY KEY (`tid`)
) ENGINE=innoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;

正则表达式

选项 匹配说明 例子 匹配值
^ 文本开始字符 '^b'匹配以字母b开头的字符串 book, big,banana,bike
. 任何单个字符 'b.t'匹配任何b和t之间有一个字符 bit, bat,but, bite
* 0个或多个在它前面的字符 'f*n'匹配字符n前面有任意n个字符f fn, fan,faan, abcn
+ 前面的字符一次或多次 'ba+'匹配以b开头后面紧跟至少一个a ba, bay,bare, battle
字符串 包含指定字符串的文本 'fa' fan, afa,faad
[字符集合] 字符集合中的任一个字符 '[xz]'匹配x或者z dizzy,zebra, x-ray, extra
[^] 不在括号中的任何字符 '[^abc]'匹配任何不包含a、b或c的字符串 desk, fox,f8ke
字符串{n} 前面的字符串至少n次 b{2}匹配2个或更多的b bbb, bbbb,bbbbbb
字符串{n,m} 前面的字符串至少n次,至多m次 b{2,4}匹配最少2个,最多4个b bb, bbb,bbbb
SELECT * FROM `teacher` WHERE `tname` REGEXP '^yang';

视图

视图(view)是一种虚拟存在的表,是一个逻辑表,本身并不包含数据。其内容由查询定义。用来创建视图的表叫基表,通过视图,可以展现基表的部分数据。视图数据来自定义视图的查询中使用的表,使用视图动态生成。

视图的优点

  1. 简单。使用视图的用户完全不需要关心后面对应的表的结构、关联条件和筛选条件,对用户来说已经是过滤好的复合条件的结果集。
  2. 安全。使用视图的用户只能访问他们被允许查询的结果集,对表的权限管理并不能限制到某个行某个列,但是通过视图就可以简单的实现。
  3. 数据独立。一旦视图的结构确定了,可以屏蔽表结构变化对用户的影响,源表增加列对视图没有影响;源表修改列名,则可以通过修改视图来解决,不会造成对访问者的影响。

视图的作用

  1. 可复用,减少重复语句书写,类似程序中函数的作用。

  2. 重构代码,分表。假如因为某种需求,需要将 user 拆成表 usera表userb,如果应用程序使用 sql 语句:select * from user那就会提示该表不存在;若此时创建视图 create view user as select a.name,a.age,b.sex from usera as a, userb as b where a.name=b.name;,则只需要更改数据库结构,而不需要更改应用程序。

  3. 逻辑更清晰,屏蔽查询细节,关注数据返回。

  4. 权限控制,某些表对用户屏蔽,但是可以给该用户通过视图来对该表操作。

    CREATE VIEW <视图名> AS <SELECT语句>
    -- 创建视图
    -- 查询 1 课程比 2 课程成绩高的所有学生的学
    号;
    CREATE VIEW view_test1 AS SELECT
    A.student_id
    FROM
    (
    SELECT
    student_id,
    num
    FROM
    score
    WHERE
    course_id = 1
    ) AS A -- 12
    LEFT JOIN (
    SELECT
    student_id,
    num
    FROM
    score
    WHERE
    course_id = 2
    ) AS B -- 11
    ON A.student_id = B.student_id
    WHERE
    A.num >
    IF (isnull(B.num), 0, B.num);

流程控制

  • IF 语句

    IF condition THEN
    ...
    ELSEIF condition THEN
    ...
    ELSE
    ...
    END IF

  • CASE 语句

    -- 相当于switch语句
    CASE value
    WHEN value THEN ...
    WHEN value THEN ...
    ELSE ...
    END CASE

  • WHILE 语句

    WHILE condition DO
    ...
    END WHILE;

  • LEAVE 语句

    -- 相当于break
    LEAVE label;

使用例子如下:

-- LEAVE语句退出循环或程序块,只能和BEGIN ... END,LOOP,REPEAT,WHILE语句配合使用
-- 创建存储过程
DELIMITER //
CREATE PROCEDURE example_leave(OUT sum INT)
BEGIN
  DECLARE i INT DEFAULT 1;
  DECLARE s INT DEFAULT 0;

  while_label:WHILE i<=100 DO
    SET s = s+i;
    SET i = i+1;
    IF i=50 THEN
      -- 退出WHILE循环
      LEAVE while_label;
       END IF;
  END WHILE;

  SET sum = s;
END
//
DELIMITER ;
-- 调用存储过程
CALL example_leave(@sum);
SELECT @sum;
  • ITERATE语句

    -- 相当于 continue
    ITERATE label

  • LOOP 语句

    -- 相当于 while(true) {...}
    LOOP
    ...
    END LOOP
    -- 可以通过LEAVE语句退出循环

使用例子如下:

-- 创建存储过程
DELIMITER
CREATE PROCEDURE example_loop(OUT sum INT)
BEGIN
  DECLARE i INT DEFAULT 1;
  DECLARE s INT DEFAULT 0;

  loop_label:LOOP
    SET s = s+i;
    SET i = i+1;

    IF i>100 THEN
      -- 退出LOOP循环
      LEAVE loop_label;  
    END IF;
  END LOOP;

  SET sum = s;
END

DELIMITER ;
-- 调用存储过程
CALL example_loop(@sum);
SELECT @sum;
  • REPEAT 语句

    -- 相当于 do .. while(condition)
    REPEAT
    ...
    UNTIL condition
    END REPEAT

使用例子如下:

DELIMITER
CREATE PROCEDURE example_repeat(OUT sum INT)
BEGIN
  DECLARE i INT DEFAULT 1;
  DECLARE s INT DEFAULT 0;

  REPEAT
    SET s = s+i;
    SET i = i+1;
    UNTIL i > 100
  END REPEAT;

  SET sum = s;
END

DELIMITER ;
-- 调用存储过程
CALL example_repeat(@sum);
SELECT @sum;

触发器

触发器(trigger)是 MySQL 提供给程序员和数据分析员来保证数据完整性的一种方法,它是与表事件相关的特殊的存储过程。它的执行不是由程序调用,也不是手工启动,而是由事件来触发,比如当对一个表进行 DML 操作(insert,delete,update)时就会激活它执行。

构成触发器的4要素如下:

  1. 监视对象:table

  2. 监视事件:insert、update、delete

  3. 触发时间:before ,after

  4. 触发事件:insert、update、delete

    CREATE TRIGGER trigger_name
    trigger_time trigger_event
    ON tbl_name FOR EACH ROW
    [trigger_order]
    trigger_body -- 此处写执行语句

    -- trigger_body: 可以一个语句,也可以是多个语句;多个语句写在 BEGIN ... END 间
    -- trigger_time: { BEFORE | AFTER }
    -- trigger_event: { INSERT | UPDATE | DELETE }
    -- trigger_order: { FOLLOWS | PRECEDES } other_trigger_name

使用例子如下:

CREATE TABLE `work` (
  `id` INT PRIMARY KEY auto_increment,
  `address` VARCHAR (32)
) DEFAULT charset = utf8 ENGINE = innoDB;
CREATE TABLE `time` (
  `id` INT PRIMARY KEY auto_increment,
  `time` DATETIME
) DEFAULT charset = utf8 ENGINE = innoDB;
-- 创建触发器
CREATE TRIGGER trig_test1 AFTER INSERT
ON `work` FOR EACH ROW
INSERT INTO `time` VALUES(NULL,NOW());

触发器的 NEW 和 OLD

在 INSERT 型触发器中,NEW 用来表示将要(BEFORE)或已经(AFTER)插入的新数据。

在 DELETE 型触发器中,OLD 用来表示将要或已经被删除的原数据。

在 UPDATE 型触发器中,OLD 用来表示将要或已经被修改的原数据,NEW 用来表示将要或已经修改为的新数据。

NEW.columnName (columnName为相应数据表某一列名)
OLD.columnName (columnName为相应数据表某一列名)

触发器的使用案例

CREATE TABLE `goods` (
  `id` INT PRIMARY KEY auto_increment,
  `name` VARCHAR (32),
  `num` SMALLINT DEFAULT 0
);
CREATE TABLE `order` (
  `id` INT PRIMARY KEY auto_increment,
  `goods_id` INT,
  `quantity` SMALLINT COMMENT '下单数量'
);
INSERT INTO goods VALUES (NULL, '手机', 40);
INSERT INTO goods VALUES (NULL, '电脑', 63);
INSERT INTO goodS VALUES (NULL, '平板', 87);
INSERT INTO `order` VALUES (NULL, 1, 3);
INSERT INTO `order` VALUES (NULL, 2, 4);

需求1:客户修改订单购买的数量,在原来购买数量的基础上减少2个

- delimiter
-- delimiter是mysql分隔符,在mysql客户端中分隔符默认是分号 ;。如果一次输入的语句较多,并且语句中间有分号,这时需要重新指定一个特殊的分隔符。
delimiter
CREATE TRIGGER trig_order_1 AFTER INSERT
ON `order` FOR EACH ROW
BEGIN
  UPDATE goods SET num = num - 2 WHERE id = 1;
END
delimiter ;
INSERT

需求2:客户修改订单购买的数量,商品表的库存数量自动改变

delimiter
CREATE TRIGGER trig_order_2 BEFORE UPDATE
ON `order` FOR EACH ROW
BEGIN
  UPDATE goods SET num=num+old.quantity - new.quantity WHERE id = new.goods_id;
END

delimiter ;
-- 测试
UPDATE `order` SET quantity = quantity+2 WHERE id = 1;

数据库游标

游标是针对行操作的,对从数据库中 select 查询得到的结果集的每一行可以进行分开的、独立的、相同或者不相同的操作。对于取出多行数据集,需要针对每行操作,可以使用游标。

游标常用于存储过程、函数、触发器、事件,游标相当于迭代器。

  • 定义游标

    DECLARE cursor_name CURSOR FOR select_statement;

  • 打开游标

    OPEN cursor_name;

  • 取游标数据

    FETCH cursor_name INTO var_name[,var_name,......]

  • 取游标数据

    FETCH cursor_name INTO var_name[,var_name,......]

  • 关闭游标

    CLOSE curso_name;

  • 释放

    DEALLOCATE cursor_name;

  • 设置游标结束标志

    DECLARE done INT DEFAULT 0;
    DECLARE CONTINUE HANDLER FOR NOT FOUND
    SET done = 1; -- done 为标记为

使用例子如下:

CREATE PROCEDURE proc_while (IN age_in INT, OUT total_out INT)
BEGIN
-- 创建 用于接收游标值的变量
DECLARE p_id,p_age,p_total INT ;
DECLARE p_sex TINYINT ; 
-- 注意:接收游标值为中文时,需要给变量 指定字符集utf8
DECLARE p_name VARCHAR (32) CHARACTER SET utf8 ; 
-- 游标结束的标志
DECLARE done INT DEFAULT 0 ;
-- 声明游标
DECLARE cur_teacher CURSOR FOR SELECT
  teacher_id,
  teacher_name,
  teacher_sex,
  teacher_age
FROM
  teacher
WHERE
  teacher_age > age_in ; -- 指定游标循环结束时的返回值 
DECLARE CONTINUE HANDLER FOR NOT found
SET done = 1 ;
 -- 打开游标
OPEN cur_teacher ;
 -- 初始化 变量
SET p_total = 0 ; 
-- while 循环
WHILE done != 1 DO
  FETCH cur_teacher INTO p_id,
  p_name,
  p_sex,
  p_age ;
    IF done != 1 THEN
        SET p_total = p_total + 1 ;
    END IF;
END WHILE ; 
-- 关闭游标
CLOSE cur_teacher ;
-- 将累计的结果复制给输出参数
SET total_out = p_total ;
END//
delimiter ;
-- 调用
SET @p_age =20;
CALL proc_while(@p_age, @total);
SELECT @total;

数据库权限管理

  • 创建用户

    CREATE USER username@host IDENTIFIED BY password;
    -- host 指定该用户在哪个主机上可以登陆,如果是本地用户可用localhost,如果想让该用户可以从任意远程主机登陆,可以使用通配符 %

  • 用户授权

    GRANT privileges ON databasename.tablename TO 'username'@'host' WITH GRANT OPTION;
    -- privileges:用户的操作权限,如SELECT,INSERT,UPDATE等,如果要授予所的权限则使用ALL
    -- databasename.tablename 如果是 . 表示任意数据库以及任意表
    -- WITH GRANT OPTION 这个选项表示该用户可以将自己拥有的权限授权给别人。
    -- 在创建操作用户的时候不指定WITH GRANT OPTION 选项导致,该用户就不能使用 GRANT 命令创建用户或者给其它用户授权.
    -- 如果不想这个用户有这个 grant 的权限,则不要加该 WITH GRANT OPTION 选项

  • 对视图授权

    GRANT select, SHOW VIEW ON databasename.tablename to 'username'@'host';

  • 刷新权限

    -- 修改权限后需要刷新权限
    FLUSH PRIVILEGES;

Mysql的远程连接

远程连接需要修改配置, 修改mysqld.cnf 中 bind-address 设置IP:

# mysqld.cnf
# vi /etc/mysql/mysql.conf.d/mysqld.cnf
bind-address=127.0.0.1

修改 mysql.user 表,可以修改用户配置.

-- 修改user表
select `user`, `host` from `mysql`.`user`;
update user set host='%' where user='root';

在MySQL的浩瀚宇宙中,我们已经穿梭于性能调优的星辰大海,遨游于复杂查询的逻辑迷宫,攀登过数据库架构设计的巍峨高峰,穿越了安全策略的迷雾森林,最终抵达了高可用性和可扩展性的广阔天地。然而,这趟旅程并非终点,而是一个新的起点。

随着技术的不断演进,MySQL的高级进阶之路充满了未知与挑战。想象一下,未来的数据库世界可能充满了人工智能的智能优化、量子计算的革命性突破,以及边缘计算的全新应用场景。在这样的背景下,我们不仅需要掌握现有的知识,更需要培养一种能够快速适应新技术、新方法的能力。

在追求技术卓越的同时,我们也不应忽视团队协作的力量。数据库专家、开发人员、系统管理员和业务分析师之间的紧密合作,是实现高效数据库解决方案的关键。通过有效的沟通和协作,我们能够将复杂的技术问题转化为实际可行的解决方案,为组织的成功奠定坚实的基础。

让我们以开放的心态迎接每一个挑战,以创新的精神探索每一个未知领域。通过不断的学习和实践,我们不仅能够提升自己的专业技能,还能够为整个数据库社区贡献自己的力量。在这个不断变化的世界里,让我们成为引领变革的先锋,用我们的智慧和热情,书写MySQL高级进阶的辉煌篇章。

记住,技术的世界没有终点,只有不断前进的旅程。让我们一起,拥抱变化,勇往直前,探索MySQL的无限可能。

相关推荐
_.Switch24 分钟前
Python 自动化运维持续优化与性能调优
运维·开发语言·python·缓存·自动化·运维开发
伏虎山真人25 分钟前
开源数据库 - mysql - mysql-server-8.4(gtid主主同步+ keepalived热切换)部署方案
数据库·mysql·开源
徐*红25 分钟前
java 线程池
java·开发语言
尚学教辅学习资料25 分钟前
基于SSM的养老院管理系统+LW示例参考
java·开发语言·java毕设·养老院
1 9 J27 分钟前
Java 上机实践4(类与对象)
java·开发语言·算法
Code apprenticeship28 分钟前
Java面试题(2)
java·开发语言
J不A秃V头A30 分钟前
Python爬虫:获取国家货币编码、货币名称
开发语言·爬虫·python
FIN技术铺3 小时前
Redis集群模式之Redis Sentinel vs. Redis Cluster
数据库·redis·sentinel
SRY122404193 小时前
javaSE面试题
java·开发语言·面试
无尽的大道4 小时前
Java 泛型详解:参数化类型的强大之处
java·开发语言