• MySQL——基础知识


    执行顺序

    • 示例代码

      select * from test
      inner join....
      where...
      group by...
      having...
      order by...
      
      -- 先根据英语成绩排序,再根据数学成绩排序,当英语成绩相同再按照数学成绩排序
      select * from TbScore order by tEnglish desc,tmath desc
      

    存储过程

    • 普通创建

      CREATE PROCEDURE p_hello()
      BEGIN
      SELECT 'Hello';
      SELECT 'world';
      END
      
      -- 调用
      call p_hello
      
    • 变量声明

      declare 变量名 数据类型 default 默认值
      
      CREATE PROCEDURE p_vartest1()
      BEGIN
      DECLARE a VARCHAR(20) DEFAULT 'abc';
      SELECT a;
      END
      -- 调用
      call p_vartest1
      
    • 变量赋值

      CREATE PROCEDURE p_vartest2()
      BEGIN
      DECLARE a INT;
      SET a = 10;
      SELECT a;
      END
      -- 调用
      CALL p_vartest2
      
    • 输入参数

    • in:输入参数,表示此参数必须再调用存储过程之前就已经被定义,定义的值就算在存储过程中被修改了,也不会改变其初始值

      CREATE PROCEDURE p_vartest3(in p_int INT)
      BEGIN
      SELECT p_int;
      set p_int = p_int + 1;
      SELECT p_int;
      END
      -- 调用
      set @p_int = 3;
      CALL p_vartest3(@p_int)
      
    • 输出参数

    • out:输出参数,该值在调用存储过程已经被定义,定义的值即使有初始值,在存储过程中也是不认可的,首次打印会是 null,如果重新赋值那么在存储过程结束之后,外部打印之前的定义的值也将会改变

      CREATE PROCEDURE p_vartest4(OUT v_out_int INT)
      BEGIN
      SELECT v_out_int;
      set v_out_int = 15;
      SELECT v_out_int;
      END
      -- 调用
      SET @v_out_int = 10;
      CALL p_vartest4(@v_out_int);
      SELECT @v_out_int
      
      CREATE PROCEDURE p_vartest5(OUT v_out_int INT)
      BEGIN
      SELECT COUNT(*) INTO v_out_int FROM comments;
      END
      -- 调用
      SET @v_out_int = 0;
      CALL p_vartest5(@v_out_int);
      SELECT @v_out_int
      
    • 输入输出参数

    • inout:综合以上两个参数的特点,即认可传入参数的初始值,也可改变初始值,外部打印会得到改变之后的值

      CREATE PROCEDURE p_vartest6(INOUT v_inout INT)
      BEGIN
      SELECT v_inout;
      SET v_inout = 10;
      SELECT v_inout;
      END
      -- 调用
      SET @v_inout = 15;
      CALL p_vartest6(@v_inout);
      SELECT @v_inout
      
    • if else

      CREATE PROCEDURE p_test1(in age int)
      BEGIN
      IF age >= 18 THEN
      	SELECT '成年人'; 
      ELSE
      	SELECT '未成年人';
      END IF;
      END
      -- 调用
      set @age= 19;
      CALL p_test1(@age);
      
      CREATE PROCEDURE p_test2(in age int)
      BEGIN
      IF age > 60 THEN
      	SELECT '老年人';
      ELSEIF 18 < age <60 THEN
      	SELECT '中年人';
      ELSE
      	SELECT '未成年';
      END IF;
      END
      -- 调用
      set @age = 50;
      CALL p_test2(@age)
      
    • case:类似 switch case

      CREATE PROCEDURE p_test3(in v int)
      BEGIN
      DECLARE adds int;
      CASE v
      	WHEN 1 THEN
      		SET adds = 1000;
      	WHEN 2 THEN
      		SET adds = 2500;
      	ELSE
      		SET adds = 3000;
      END CASE;
      UPDATE comments set user_id = adds WHERE id = 2;
      END
      -- 调用
      SET @v = 2;
      CALL p_test3(@v)
      
    • 还可以直接在查询语句中使用

    • https://www.cnblogs.com/raobenjun/p/7998467.html

      -- 如果参数1为true,则返回参数2,否则返回参数3
      SELECT IF(`user`.`name`>23,`user`.`name`,1000) FROM `user` WHERE id = 83
      
      SELECT  topic_id, (case user_id WHEN 2500 THEN 8888 ELSE 7777 END) as user_id  FROM comments
      
    • ifnull(exp1, exp2):exp1 如果是空值,那么返回结果就是 exp2,如果 exp1 不是控制,那么就返回 exp1

      SELECT IFNULL(NULL,'not null') as result
      
    • while:循环语句

      -- 1——100累加
      CREATE PROCEDURE p_test4()
      BEGIN
      DECLARE i int DEFAULT 1;
      DECLARE adds int DEFAULT 0;
      WHILE i <= 100 DO
      	set adds = adds + i;
      	set i = i + 1;
      END WHILE;
      SELECT adds;
      END
      -- 调用
      CALL p_test4()
      
      -- 更改表数据
      CREATE PROCEDURE p_test5()
      BEGIN
      DECLARE i int DEFAULT 0;
      DECLARE maxV int DEFAULT 0;
      WHILE i <= 100 DO
      	SELECT MAX(id) into maxV FROM comments;
      	SET maxV = maxV + 1;
      	INSERT INTO comments (commet, user_id, topic_id) VALUES (maxV, maxV, maxV);
      	SET i = i + 1;
      END WHILE;
      END
      -- 调用
      CALL p_test5()
      
    • repeat:循环语句

      -- 偶数行改变
      CREATE PROCEDURE p_test6()
      BEGIN
      DECLARE minV int DEFAULT 1;
      DECLARE maxV int DEFAULT 2;
      SELECT min(id) into minV FROM comments;
      SELECT max(id) into maxV FROM comments;
      REPEAT
      	IF minV % 2 = 0 THEN
      		UPDATE comments SET user_id = 999 WHERE id = minV;
      	END IF;
      	SET minV = minV +1;
      UNTIL minV > maxV END REPEAT;
      END
      -- 调用
      CALL p_test6()
      
    • loop:循环语句

      -- 奇数行改变
      CREATE PROCEDURE p_test7()
      BEGIN
      DECLARE minV INT DEFAULT 1;
      DECLARE maxV INT DEFAULT 1;
      SELECT min(id) INTO minV FROM comments;
      SELECT max(id) INTO maxV FROM comments;
      myloop: LOOP
      	IF minV % 2 = 1 THEN
      		UPDATE comments SET user_id = 555 WHERE id = minV;
      	END IF;
      	SET minV = minV + 1;
      	IF minV > maxV THEN
      		LEAVE myloop; 
      	END IF; 
      END LOOP;
      END
      -- 调用
      CALL p_test7()
      
    • continue handler:捕获存储过程中的错误并继续执行,不常用

      declare continue handler for sqlstate '23000' set @x=1;
      
    • 查看存储过程

      -- 查看数据库下存储过程
      show procedure status where db='数据库'
      
    • 删除存储过程

      drop procedure if exists 存储过程名字
      drop procedure if exists p_hello
      

    自定义函数

    • 开启服务:必须先确认是否有设置自定义函数权限

      -- 查看是否有权限
      show variables like '%fun%';
      -- 手动开启权限
      set global log_bin_trust_function_creators = 1;
      
    • 创建函数

      create function fun_add( a int, b int)
      returns int
      begin 
      	return a+b;
      end;
      -- 调用
      select fun_add(3,4)
      

    触发器

    • 触发器是特殊的存储过程,表示的是对表进行插入、修改、删除操作时候触发的一个钩子

    • 监视动作:update、delete、insert

    • 触发时间:after、before

      -- 语法
      create trigger trigger_name trigger_time trigger_event on tbl_name for each row trigger_stmt
      
      -- new 代表刚插入一行的信息
      create triger tri_insertComment after insert on comments for each row
      begin
      	insert monitor values (new.content, new.createAt);
      end;
      

    事务

    • 是否支持

      -- InnoDB 才支持事务操作
      show variables like '%storage_engine%'
      
    • 开始事务

      start transaction;
      insert into comments (user_id, topic_id) values (123,123);
      insert into user (name) values ('Judy');
      commit;
      
      -- commit and chain 表示提交之后再次开启新的事务
      start transaction;
      insert into comments (user_id, topic_id) values (123,123);
      commit and chain;
      insert into user (name) values ('Judy');
      commit;	
      
      -- savepoint s1 表示设置还原点
      start transaction;
      insert into comments (user_id, topic_id) values (123,123);
      savepoint s1;
      insert into comments (user_id, topic_id) values (123,124);
      savepoint s2;
      insert into comments (user_id, topic_id) values (123,125);
      savepoint s3;
      insert into comments (user_id, topic_id) values (123,126);
      savepoint s4;
      rollback to savepoint s2;
      commit;	
      
      -- 事务中只要出现错误就回滚到原始状态
      CREATE PROCEDURE p_tran()
      BEGIN
      DECLARE t_error INT;
      DECLARE CONTINUE HANDLER FOR SQLEXCEPTION SET t_error = 1;
      START TRANSACTION;
      	INSERT INTO comments (user_id,topic_id) VALUES (456,457);
      	INSERT INTO comments (user_id,ddddddddd) VALUES (458,459);
      	IF t_error = 1 THEN
      		ROLLBACK;
      	ELSE
      		COMMIT;
      	END IF;
      END
      -- 调用
      CALL p_tran()
      
    • rollback and release:表示事务回滚之后端口与客户端连接

    游标

    • 游标帮助我们遍历表中的每一行数据

    • 帮助文档:https://www.cnblogs.com/lyhc/p/5760164.html

      CREATE PROCEDURE p_cur()
      BEGIN
      -- 连接字符串
      DECLARE str VARCHAR(100) DEFAULT 'start';
      -- 存储遍历的一列数据
      DECLARE topic_id_c INT(11); 
      -- 遍历结束标志 
      DECLARE done INT DEFAULT FALSE; 
      -- 声明游标
      DECLARE cur_account CURSOR FOR SELECT topic_id FROM comments where user_id = 123;
      -- 将结束标识进行绑定,游标报错一般就是:NOT FOUND
      DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
      -- 打开游标
      OPEN cur_account;
      -- 遍历
      read_loop: LOOP
              -- 抓取每一行数据赋值到对应字段
      	FETCH NEXT FROM cur_account into topic_id_c;
      	IF done THEN
      		LEAVE read_loop; 
      	END IF; 
              -- 做自己想做的事
      	SELECT CONCAT(str,'|',topic_id_c) INTO str;
      END LOOP;
      CLOSE cur_account;
      SELECT str;
      END
      -- 调用
      CALL p_cur()
      

    数据转换

    合并数据

    • 多表联合查询,特别是一对多的情况下,需要将外键表进行有效压缩

    • GROUP_CONCAT:多行数据合并一行,也可以将多列数据合并成一列,指定分割符号,GROUP_CONCAT(r.role_name SEPARATOR '|'),这样的方式同样可以删除连接符

    • CONACT:多列数据合并成一列,需要配个 IFNULL 使用,因为只要其中有一列是空值,合并就失败了

    • 列1+列2:计算两个列的合,注意其中有一列为NULL,那么结果都为NULL,所以计算前最好用 IFNULL 进行判断

    • SELECT GREATEST(1,NULL):判断并返回最大值,同样也有上述问题,最好使用 IFNULL 进行判断

    • 帮助文档

    • 示例代码

      SELECT tc.id, tc.title, tc.content, GROUP_CONCAT(cm.user_id) as users FROM topics as tc inner join comments as cm on tc.id = cm.topic_id GROUP BY id ORDER BY tc.id
      
        -- concat 是简单的多列合并,group_concat 是进行依据分组进行纵向(行)合并
      SELECT topics.id, topics.title, topics.content, GROUP_CONCAT(CONCAT(topics.user_id,'|',CASE `user`.`avater` WHEN '' THEN 'null' ELSE `user`.`avater` END))  as info  FROM topics INNER JOIN comments ON topics.id = comments.topic_id 
      INNER JOIN `user` ON topics.user_id = `user`.id
      GROUP BY topics.id
      
      -- 最保险的写法,将查询结果作为连接查询的表,结构清晰
        
      SELECT 
        
      topics.*,
        
      users.username, users.avatar,
        
      new_topics_like.like_user_id,
        
      new_topics_collection.collection_user_id
        
      FROM topics
        
      INNER JOIN users ON topics.user_id = users.id
        
      LEFT JOIN (SELECT topics_like.topic_id, GROUP_CONCAT(topics_like.user_id) as like_user_id FROM topics_like WHERE topics_like.deletedAt is NULL GROUP BY topics_like.topic_id) as new_topics_like ON topics.id = new_topics_like.topic_id
        
      LEFT JOIN (SELECT topics_collection.topic_id, GROUP_CONCAT(topics_collection.user_id) as collection_user_id FROM topics_collection WHERE topics_collection.deletedAt is NULL GROUP BY topics_collection.topic_id) as new_topics_collection ON topics.id = new_topics_collection.topic_id
        
      WHERE topics.id = 38 AND topics.deletedAt is null LIMIT 1
      

    联表查询

    • inner join:适合严格一对一,虽然是一个表依赖另一个表(外键),但是并没有构成一对多的关系

    • left join:当查询表是主表,对副表进行连接查询,构成一对多的关系,适合使用左联,因为情况往往是主表是肯定存在的,但是副表不一定有对应数据,此时还使用 inner join 将不会查询到任何结果,而且遗漏了主表数据;如果是多对一的话,还是适合 inner join 进行查询

    • 个人觉的多表联合查询,可以借用变量。例如,借用 JS 变量存储某个表格,最后用一个总的变量去连接上述已经存储表的变量

      // -- users
      var users = "select * from users where deletedAt is null"
      
      var topics = "select * from topics where deletedAt is null"
      
      // -- comments 
      var comments = "select * from comments where deletedAt is null and user_id =88"
      
      // -- comments inner join user
      
      var result_c = `select 
      
      new_comments.id, left(new_comments.content, 100) as content, new_comments.createdAt, new_users.avatar, new_users.username, new_comments.topic_id, new_topics.title as targetContent, 'parent' as targetCategory from (${comments}) as new_comments 
      
      inner join (${users}) as new_users on new_users.id = new_comments.user_id
      
      inner join (${topics}) as new_topics on new_topics.id = new_comments.topic_id`
      
      // -- comments_son
      var comments_son = "select * from comments_son where deletedAt is null and user_id = 88"
      
      // -- comments_son inner join users | comments_son inner join comments  
      var result_cs = `select 
      
      new_comments_son.parent_comment_id as id, left(new_comments_son.content,100) as content, new_comments_son.createdAt, new_users.avatar, new_users.username, new_comments.topic_id, left(new_comments.content,100) as targetContent, 'son' as  targetCategory 
      
      from (${comments_son}) as new_comments_son
      
      inner join (${users}) as new_users on new_users.id = new_comments_son.user_id
      
      inner join (${comments}) as new_comments on new_comments.id = new_comments_son.parent_comment_id`
      
      
      var result = `(${result_c}) union (${result_cs})`
      
      console.log(result)
      

    外键设置

    帮助文档

  • 相关阅读:
    启动Nginx、查看nginx进程、nginx帮助命令、Nginx平滑重启、Nginx服务器的升级
    专为渗透测试人员设计的 Python 工具大合集
    如何为网站启用HTTPS加密传输协议
    正确设置nginx/php-fpm/apache权限 提高网站安全性 防止被挂木马
    java中十进制转换为任意进制
    多线程死锁的产生以及如何避免死锁
    Java Integer和String内存存储
    Java 内存溢出(java.lang.OutOfMemoryError)的常见情况和处理方式总结
    Jvm垃圾回收器详细
    分布式环境中的负载均衡策略
  • 原文地址:https://www.cnblogs.com/cnloop/p/9424801.html
Copyright © 2020-2023  润新知