MySQL基础

MySQL服务的启动和停止

  方式一:计算机 - 右击管理 - 服务
  方式二:以管理员身份运行命令行
                 net start 服务名(启动服务)
                 net stop 服务名(停止服务)

MySQL服务的登陆和退出

   方式一:通过MySQL自带的客户端(有局限性,只限于root用户)
   
   方式二:通过windows自带的客户端(以管理员身份运行命令行)

     登陆:
              mysql  [-h主机名 -P端口号] -u用户名 -p密码
              (注意:如果是本机,-h主机名 -P端口号可以省略,-p密码之间不允许有空格,其它可以有空格,也可无空格)
     退出:
              exit 或 ctrl + c(我尝试ctrl+c不管用) 或 \q 或 quit

     注意:如果执行 mysql  [-h主机名 -P端口号] -u用户名 -p密码 命令,结果显示:
                  【 "mysql" 不是内部或外部命令,也不是可运行的程序或批处理文件】
          则需要把MySQL的安装的bin目录配置到path环境变量中.

MySQL的常见命令

   1、查看当前所有的数据库
              show databases;
   2、打开指定的库
              use 库名;
   3、查看当前库的所有表
              show tables;
   4、查看其它库的所有表
              show tables from 库名;
        (注意:此命令是在当前库查看其它库的所有表)
   5、查看当前位于哪个库
              select database();
   6、 创建表
              create table 表名(
                     列名  列类型,
                     列名  列类型,
                     .......
               );
   7、查看表结构
                desc 表名;
     
   8、查看服务器的版本
           方式一:登陆到mysql 服务端
                          select version();
           方式二:没有登陆mysql服务端(以管理员身份运行命令行)
                           mysql  --version
                      或
                           mysql  -V

MySQL的语法规范

  1、不区分大小写,但建议关键字大写,表名、列名小写
  2、每条命令最好用分号结尾
  3、每条命令根据需要,可以进行缩进 或换行
  4、MySQL中可以使用单引号也可以使用双引号
  5、注释
              单行注释:#注释文字  或者  -- 空格 注释文字
              多行注释:/* 注释文字  */

SQL的语言分类

   DQL (Data Query Language):数据查询语言  【select】
   
   DML (Data Manipulate Language):数据操作语言  【insert 、update、delete】                      
 
   DDL (Data Define Language):数据定义语言 【create、drop、alter】

   TCL (Transaction Control Language):事务控制语言 【commit、rollback】

DQL语言的学习

进阶一:基础查询

 特点:
      ①通过select查询完的结果 ,是一个虚拟的表格,不是真实存在
      ② 要查询的东西 可以是常量值、可以是表达式、可以是字段、可以是函数
 1、查询单个字段、多个字段、所有字段;
 2、查询常量值: select  100;    select 'join';
       注意:字符型和日期型的常量值必须用单引号括起来,数值型不需要;
 3、查询表达式: select 90 * 100;
 4、查询函数(必须要有返回值):   select  version();
 5、起别名:AS   或者  空格
     
        例如:  select 100 % 98 AS 结果;
               select 100 % 98  结果;
               select 100 % 98 AS  "OUT PUT";

6、DISTINCT :去重

7、MYSQL中 + 的作用:仅仅只有一个功能,即运算符
       ①、两个操作数都为数值,则做加法运算;
                 select 100 + 90;
       ②、如果其中一方为字符型,试图将字符型数值转换成数值型,
          如果转换成功,则继续做加法运算;     select '123' + 90;    ---> 213
          如果转换失败,则将字符型数值转换为0进行加法运算;  select 'join' + 90;  ---> 90
       ③、如果其中一方为null,则结果肯定为null ; select  null + 10;   ---> null

8、使用CONCAT函数实现字符连接:select CONCAT('a','b','c') as 结果; ---> abc
                            select CONCAT('a','null','c') as 结果; ---> anullc
                            select CONCAT('a',null,'c') as 结果; ---> null     只要有一个值为null,则结果为null

9、ifnull 函数功能:判断某字段或表达式的值是否为null,如果为null,返回指定的值,否则返回原本的值
       select  ifnull(commission_pct, 0) from employees;   -->如果将近率commission_pct为null,则返回0,如果不为null,则返回原本的值

10、isnull 函数功能:判断某字段或表达式的值是否为null,如果为null,则返回1(表示true),否则返回0(表示false)
       select  isnull(commission_pct) from employees;  

进阶二:条件查询

    1、条件查询:根据条件过滤原始表的数据,查询到想要的数据
    2、语法:
          select  要查询的字段|表达式|常量值|函数  
          from 表  
          where 条件 ;
    3、分类:
        一、条件表达式  示例:salary>10000
            条件运算符:  >、 <、 >=、 <=、 =、 !=、 <>
        
        二、逻辑表达式    示例:salary>10000 && salary<20000
            逻辑运算符:
                      and(&&):两个条件如果同时成立,结果为true,否则为false
                      or(||):两个条件只要有一个成立,结果为true,否则为false
                      not(!):如果条件成立,则not后为false,否则为true
        
       三、模糊查询 :like、between and 、in 、is null  或 is not null
               *  like特点:
                         ①、一般和通配符搭配使用,可以判断字符型或者数值型
                             通配符:
                                  % :任意多个字符,包含0个字符
                                  _  : 任意单个字符
                       
                        示例:last_name like 'a%';
                             或者
                             department_id like '2%';
                             或者
                             last_name like '_$_%'  ESCAPE '$';   转义字符,第二个字符为_
                             或者
                             last_name like '_\_%'  ;   转义字符,第二个字符为_
             
               *  between and 特点:
                         ①、包含临界值,等价于 >=  and  <= ,所以两个临界值之间顺序不可以互换
          
               *  is null 或 is not null 特点:
                         ①、= 或 <> 不能用于判断 null 值;
                         ②、is null 或 is not null 只能用于判断 null 值;
  
               * <=> 表示安全等于,既可以用于判断null值,也可以用于判断普通的数值,可读性较低 
                           
                       示例:1、查询没有奖金的员工
                                  select * from employees where commission_pct is null;
                                 或
                                  select * from employees where commission_pct <=> null;
                            2、查询工资为12000的员工
                                  select * from employees where salary<=> 12000;
                                 或
                                  select * from employees where salary = 12000;
        案例: 
          1、查询员工号为176的员工的姓名和部门号以及年薪
            select employee_id, department_id, salary*12*(1 + IFNULL(commission,0)) from employees where employee_id = 176  
          
          2、经典面试题
              ①、试问 select * from employees; 和 select * from employees where commission_pct like '%%' and last_name like '%%';结果是否一样,请说明原因
                     不一样,因为commission_pct 可能为null
             ②、 试问 select * from employees; 和 select * from employees where commission_pct like '%%' or last_name like '%%' or employee_id like '%%';结果是否一样,请说明原因
                     一样,因为是用or 连接,总有一个字段是没有null值的

进阶三:排序查询

  语法:
         select  查询列表
         from  表名
         where  条件
         order by 排序的字段(单个或者多个字段) | 表达式 | 函数 | 别名 【asc|desc】
  特点:
        1、asc 代表升序,desc代表降序,如果不写,默认为升序
        2、order by 子句一般放在查询语句的最后面,limit 子句除外

进阶四:常见函数

 一、单行函数
      1、字符函数
          concat(str1, str2, str3, str4......):拼接字符

          substr / substring:截取字符       【 注意:索引是从1开始的】

          upper(str):把参数值转换成大写
          lower(str):把参数值转换成小写

          trim:去除前后指定的空格和字符
          例如:
             select trim('        张三     ');      --->  去除前后空格
             select trim('a' from 'aaaaa张aaaa三aaaaaa');    ---> 去除前后指定字符a,结果为:张aaaa三

          ltrim:去左边空格
          rtrim:去右边空格

          replace(str, from_str, to_str):替换,把 str 中所有的 from_str 替换成 to_str 

          lpad(str, len, padstr):用指定的字符padstr 左填充 str 到指定的长度 len【注意是字符个数,不是字节个数】,如果str 超过了指定的长度len,则对str 进行右截取  
          rpad(str, len, padstr):用指定的字符padstr 右填充 str 到指定的长度 len【注意是字符个数,不是字节个数】,如果str 超过了指定的长度len,则对str 进行右截取  

          instr(str, substr):返回子串 substr 在 str 中第一次出现的索引,如果没有找到,则返回0

          length(str): 获取参数值的字节个数(对于中文,utf8 -> 一个汉字3个字节,GBK -> 一个汉字2个字节)

    
      2、数学函数
          round :四舍五入
              例如:select round(1.46);   ---> 1
                   select round(-1.56);   ---> -2   (如果是负数,先取绝对值进行四舍五入,然后再加上负号) 
                   select round(1.678, 2);   ---> 小数点后保留2位,结果为:1.68

          rand :rand函数用于产生0(包含)到1(不包含)的随机数   
            rand有两种形式:
                  1、rand(),即无参数的,此时产生的随机数是随机的,不可重复的;
                  2、rand(n),即有参数的,如rand(2),相当于指定随机数生产的种子,那么这种情况产生的随机数是可重复的。

          floor向下取整,返回小于等于该参数的最大整数
              例如: select floor(1.99);    ---> 1
                    select floor(-9.99);      ---> -10

          ceil(x):向上取整,返回大于等于该参数的最小整数
              例如: select ceil(1.002);    ---> 2
                    select ceil(1.00);      ---> 1
                    select ceil(-1.002);   ---> -1

          mod(n, m):取余(n - n / m * m)  【注意:如果n 为负数,则结果为负数,如果n为正数,则结果为正数】
              例如:select mod(10, 3);        ---> 1
                   select mod(-10, -3);      ---> -1
                   select mod(10, -3);       --->  1         

          truncate(X, D):截断
              例如: select truncate(1.6999, 1);   --->表示小数点后保留1位,其余截断,即:1.6

      3、日期函数
          now:返回当前系统的日期+时间          select now();
            
          curdate:返回当前系统的日期,不包含时间      select curdate();
          curtime:返回当前系统的时间,不包含日期      select curtime();
    
          可以获取指定的部分,比如:年、月、日、时、分、秒
          select year(now()) 年,month(now()) 月 ,day(now()) 日,hour(now()) 时 ,minute(now()) 分 ,second(now())  秒;                 
          select monthname(now()) 月;            --->获取月份的英文名称

          str_to_date: 将日期格式的字符转换成指定格式的日期
                例如:select str_to_date('4-3 1993', '%c-%d %y');
        
               格式符                          功能
               %Y                            四位的年份
               %y                            2位的年份
               %m                            月份(01, 02, ... 11, 12)
               %c                            月份(1, 2, ... 11, 12)
               %d                            日(01, 02, ...)
               %H                            小时(24小时制)
               %h                            小时(12小时制)
               %i                            分钟(00, 01, ... 59)
               %s                            秒(00, 01, ... 59)

          date_format(date, format):将日期转换成字符
            例如:select date_format(now(), '%y年%m月%d日');

          datediff(expr,expr2):求两个日期之间相差的天数

     4、流程控制函数
          ①、if(expr1, expr2, expr3) : 处理双分支,相当于if else 的效果,对于表达式expr1,如果表达式成立为true,则返回expr2的值,否则返回expr3的值;
          
             例如:select if(10 > 5, '正确', '错误');
             
          ②、case语句 :处理多分支
                 情况1:处理等值判断
                       语法:
                           case 要判断的字段或表达式
                           when 常量1  then 要显示的值1或语句1【如果是语句,要加分号,如果是值,则不加分号】
                           when 常量2  then 要显示的值2或语句2
                           .....
                           else  要显示的值n 或 语句n
                           end

                 例如:查询员工的工资,要求,如果部门号=30,显示的工资为1.1倍,
                                         如果部门号=40,显示的工资为1.2倍,
                                         如果部门号=50,显示的工资为1.3倍,
                                         其他部门,显示的工资为原工资
                     select salary 原始工资, department_id,
                                case department_id
                                when 30 then salary * 1.1
                                when 40 then salary * 1.2
                                when 50 then salary * 1.3
                                else salary 
                                end as 新工资
                     from employees;
            
              情况2:处理条件判断
                    语法:
                           case 
                           when 条件1  then 要显示的值1或语句1【如果是语句,要加分号,如果是值,则不加分号】
                           when 条件2  then 要显示的值2或语句2
                           .....
                           else  要显示的值n 或 语句n
                           end
                
                 例如:查询员工的工资情况,要求,如果工资 > 20000,显示A级别,
                                             如果工资 > 15000,显示B级别,
                                             如果工资 > 10000,显示C级别,
                                             否则显示D级别
                     select salary,
                            case 
                            when salary > 20000 then 'A'
                            when salary > 15000 then 'B'
                            when salary > 10000 then 'C'
                            else 'D'
                            end as 工资级别
                     from employees;

     5、其他函数
         version:版本          select version();
         database:当前库       select database();
         user:当前连接用户      select user();
         password('字符'):返回该字符的加密形式
         md5('字符'):返回该字符的md5加密形式


二、分组函数,用做统计使用,又称为 统计函数 或 聚合函数 或 组函数
         sum :求和
         max :最大值
         min :最小值
         avg :平均值
         count :计数

    特点:
        1、以上五个分组函数都忽略null值,除了count(*)
        2、sum 和 avg 一般用于处理数值型, max、min、count 可以处理任何数据类型
        3、都可以搭配distinct使用,用于统计去重后的结果
        4、count的参数可以支持: 字段、*、常量值,一般放1
        5、和分组函数一同查询的字段要求是group by 后的字段

         建议使用 count(*)

进阶五:分组查询

 语法:
        select 分组函数, 查询的字段(要求必须出现才group by 后面的)
        from 表
        【where 筛选条件】
        group by 分组的字段
        【order by 子句】

 注意: 查询列表比较特殊,要求是分组函数和 group by 后面的出现的字段
 
 特点:
      
      1、和分组函数一同查询的字段最好是分组后的字段
      2、分组查询中的筛选条件分为两类
                    针对的表                    位置                   关键字
       分组前筛选:   原始表                   group by子句的前面          where
       分组后筛选:   分组后的结果集            group by子句的后面          having
       
       ①、分组函数做条件肯定是放在having子句中
       ②、能用分组前筛选的就优先考虑使用分组前筛选的

      3、group by 子句可以支持按单个字段分组, 也可以支持按多个字段分组, 字段之间用逗号隔开, 没有顺序要求,也可以支持表达式或函数分组
      4、可以支持排序(排序放在整个分组查询的最后)
      5、having 、order by 后可以支持别名

进阶六:连接查询

 1、连接查询又称为多表查询,当查询的字段来自于多个表时,就会用到连接查询
 2、笛卡尔乘积现象:表1  有 m 行,表2有 n 行,结果有 m*n 行
       * 发生的原因:没有有效的连接条件
       * 如何避免:添加有效的连接条件
 3、分类
       * 按年代分类:

         ①、sql 92标准:在MySQL中仅仅支持内连接
           * 内连接
                等值连接:
                        -  多表等值连接的结果为多表的交集部分
                        -  n 表连接,至少需要 n - 1 个连接条件
                        -  多表的顺序没有要求, 多表没有主次
                        -  一般需要为表起别名, 提高阅读性和性能
                        -  可以搭配比如:排序、分组、筛选等子句使用
                    语法:
                        select  查询列表
                        from 表1 别名, 表2 别名
                        where 表1.key = 表2.key
                        【and 筛选条件】
                        【group by 筛选条件】
                        【having 筛选条件】
                        【order by 排序字段】
                   
                     例如:查询每个工种的工种名和员工的个数,并且按员工个数降序
                          SELECT job_title,COUNT(*)
                          FROM employees e,jobs j
                          WHERE e.`job_id`=j.`job_id`
                          GROUP BY job_title
                          ORDER BY COUNT(*) DESC;

                非等值连接:
                      语法:
                            select  查询列表
                            from 表1 别名, 表2 别名
                            where 非等值的连接条件
                            【and 筛选条件】
                            【group by 筛选条件】
                            【having 筛选条件】
                            【order by 排序字段】

                      例如:查询员工的工资和工资级别
                            SELECT salary,grade_level
                            FROM employees e,job_grades g
                            WHERE salary BETWEEN g.`lowest_sal` AND g.`highest_sal`
                            AND g.`grade_level`='A';

                自连接:
                      语法:
                            select  查询列表
                            from 表 别名1, 表  别名2
                            where  等值的连接条件
                            【and 筛选条件】
                            【group by 筛选条件】
                            【having 筛选条件】
                            【order by 排序字段】

                      案例:查询员工名和上级的名称
                            SELECT e.employee_id,e.last_name,m.employee_id,m.last_name
                            FROM employees e,employees m
                            WHERE e.`manager_id`=m.`employee_id`;

         ②、sql99 标准(推荐):支持内连接、外连接(左外连接+右外连接,不支持全外连接)、交叉连接
              语法:
                        select  查询列表
                        from 表1 别名  
                        【连接类型 inner|left outer|right outer|cross】   join  表2 别名   on  连接条件
                        【连接类型 inner|left outer|right outer|cross】   join  表3 别名   on  连接条件
                        【where 筛选条件】
                        【group by 分组】
                        【having  筛选条件】
                        【order by 排序列表】

              * 内连接 : inner 

                      特点:
                           1、 可以添加排序、分组和筛选等;
                           2、inner 可以省略;
                           3、筛选条件放在where后面,连接条件放在on后面,提高分离性,便于阅读;
                           4、inner join 连接和sql92 语法中的等值连接效果是一样的,都是查询多表的交集部分

                  - 等值连接:
                        举例:
                           1、查询哪个部门的员工个数>3的部门名和员工个数,并按个数降序(添加排序)
                             SELECT COUNT(*) 个数,department_name
                             FROM employees e
                             INNER JOIN departments d
                             ON e.`department_id`=d.`department_id`
                             GROUP BY department_name
                             HAVING COUNT(*)>3
                             ORDER BY COUNT(*) DESC;

                           2、三表连接:查询员工名、部门名、工种名,并按部门名降序
                            SELECT last_name,department_name,job_title
                            FROM employees e
                            INNER JOIN departments d ON e.`department_id`=d.`department_id`
                            INNER JOIN jobs j ON e.`job_id` = j.`job_id`
                            ORDER BY department_name DESC;

                  - 非等值连接:
                        举例:查询工资级别的个数>20的个数,并且按工资级别降序
                              SELECT COUNT(*),grade_level
                              FROM employees e
                              JOIN job_grades g
                              ON e.`salary` BETWEEN g.`lowest_sal` AND g.`highest_sal`
                              GROUP BY grade_level
                              HAVING COUNT(*)>20
                              ORDER BY grade_level DESC;

                  - 自连接:
                        举例:查询姓名中包含字符k的员工的名字、上级的名字
                                 SELECT e.last_name,m.last_name
                                 FROM employees e
                                 JOIN employees m
                                 ON e.`manager_id`= m.`employee_id`
                                 WHERE e.`last_name` LIKE '%k%';
                           
              * 外连接
                    应用场景:用于查询一个表中有,另一个表没有的记录

                    特点:
                           1、外连接的查询结果为主表中的所有记录
                              如果从表中有和它匹配的,则显示匹配的值
                              如果从表中没有和它匹配的,则显示null
                              外连接查询结果=内连接结果+主表中有而从表没有的记录
                           2、左外连接,left  join左边的是主表
                              右外连接,right join右边的是主表
                           3、左外和右外交换两个表的顺序,可以实现同样的效果 
                           4、全外连接=内连接的结果 + 表1中有但表2没有的 + 表2中有但表1没有的

                    左外连接  : left  【outer】
                    右外连接  : right 【outer】
                     
                             案例:查询哪个部门没有员工
                                 #左外
                                        SELECT d.*,e.employee_id
                                        FROM departments d
                                        LEFT OUTER JOIN employees e
                                        ON d.`department_id` = e.`department_id`
                                        WHERE e.`employee_id` IS NULL;


                                 #右外
                                         SELECT d.*,e.employee_id
                                         FROM employees e
                                         RIGHT OUTER JOIN departments d
                                         ON d.`department_id` = e.`department_id`
                                         WHERE e.`employee_id` IS NULL;
                 
                   全外连接  : full  【outer】

              * 交叉连接 :cross (sql 99语法中的笛卡尔乘积)
                        
                       举例 : 
                               SELECT b.*,bo.*
                               FROM beauty b
                               CROSS JOIN boys bo;

     * 按功能分类
         ①、内连接
         ②、外连接
                    左外连接
                    右外连接
                    全外连接
         ③、交叉连接

进阶七:子查询

  1、含义:出现在其他语句中的select语句,称为子查询或内查询
          外部的查询语句,称为主查询或外查询

  2、分类:
      * 按子查询出现的位置:
             select后面:仅仅支持标量子查询
                      
                  #案例:查询每个部门的员工个数
                               SELECT d.*,(
                                     SELECT COUNT(*)
                                     FROM employees e
                                     WHERE e.department_id = d.`department_id`
                               ) 个数
                               FROM departments d;

             from后面:支持表子查询, 将子查询结果充当一张表,要求必须起别名
                        
                  #案例:查询每个部门的平均工资的工资等级
                          #①查询每个部门的平均工资
                                  SELECT AVG(salary),department_id
                                  FROM employees
                                  GROUP BY department_id

                          #②连接①的结果集和job_grades表,筛选条件平均工资 between lowest_sal and highest_sal
                                  SELECT  ag_dep.*,g.`grade_level`
                                  FROM (
                                        SELECT AVG(salary) ag,department_id
                                        FROM employees
                                        GROUP BY department_id
                                  ) ag_dep
                                  INNER JOIN job_grades g
                                  ON ag_dep.ag BETWEEN lowest_sal AND highest_sal;

             where或having后面:
                        标量子查询(单行子查询) √
                        列子查询  (多行子查询) √
                        行子查询  (结果集为一行多列 或 多行多列)
                
                  特点:
                     ①、子查询放在小括号内
                     ②、子查询一般放在条件的右侧
                     ③、标量子查询,一般搭配着单行操作符使用   >、 < 、>=、 <=、 =、 <>
                        列子查询,一般搭配着多行操作符使用    in、any/some、all
                        例如:> any/some(子查询); 意思是大于子查询中的最小值即可【可以使用MIN()函数代替】
                             > all(子查询);      意思是大于子查询中的最大值即可【可以使用MAX()函数代替】
                     ④、子查询的执行优先于主查询执行,主查询的条件用到了子查询的结果

                 #1.标量子查询(单行子查询)                        
                      案例1:返回job_id与141号员工相同,salary比143号员工多的员工 姓名,job_id 和工资

                          #①查询141号员工的job_id
                                  SELECT job_id
                                  FROM employees
                                  WHERE employee_id = 141

                          #②查询143号员工的salary
                                  SELECT salary
                                  FROM employees
                                  WHERE employee_id = 143

                          #③查询员工的姓名,job_id 和工资,要求job_id=①并且salary>②
                                  SELECT last_name,job_id,salary
                                  FROM employees
                                  WHERE job_id = (
                                              SELECT job_id
                                              FROM employees
                                              WHERE employee_id = 141
                                  ) AND salary>(
                                              SELECT salary
                                              FROM employees
                                              WHERE employee_id = 143
                                  );
                  
                      案例2:查询最低工资大于50号部门最低工资的部门id和其最低工资

                          ①查询50号部门的最低工资
                                  SELECT  MIN(salary)
                                  FROM employees
                                  WHERE department_id = 50

                          ②查询每个部门的最低工资
                                  SELECT MIN(salary),department_id
                                  FROM employees
                                  GROUP BY department_id

                          ③ 在②基础上筛选,满足min(salary)>①
                                  SELECT MIN(salary),department_id
                                  FROM employees
                                  GROUP BY department_id
                                  HAVING MIN(salary)>(
                                            SELECT  MIN(salary)
                                            FROM employees
                                            WHERE department_id = 50
                                  );

                 #2、列子查询(多行子查询)                        
                      案例1:返回location_id是1400或1700的部门中的所有员工姓名

                          ①查询location_id是1400或1700的部门编号
                                  SELECT DISTINCT department_id
                                  FROM departments
                                  WHERE location_id IN(1400,1700);

                          ②查询员工姓名,要求部门号是①列表中的某一个
                                  SELECT last_name
                                  FROM employees
                                  WHERE department_id  in (
                                            SELECT DISTINCT department_id
                                            FROM departments
                                            WHERE location_id IN(1400,1700)
                                  );

                             # 等价于

                                  SELECT last_name
                                  FROM employees
                                  WHERE department_id  =any (
                                            SELECT DISTINCT department_id
                                            FROM departments
                                            WHERE location_id IN(1400,1700)
                                  );
                        
                          #注意:in 等价于 =any 、 not in 等价于 <>all、<any 等价于 < max()、<all 等价于 <min()、>any 等价于 > min()、>all 等价于 >max()

                      案例2:返回其它工种中比job_id为‘IT_PROG’工种任一工资低的员工的员工号、姓名、job_id 以及salary

                          #①查询job_id为‘IT_PROG’部门任一工资
                                  SELECT  DISTINCT salary
                                  FROM employees
                                  WHERE job_id = 'IT_PROG'

                          #②查询员工号、姓名、job_id 以及salary,salary<(①)的任意一个
                                  SELECT last_name,employee_id,job_id,salary
                                  FROM employees
                                  WHERE salary <ANY(
                                            SELECT DISTINCT salary
                                            FROM employees
                                            WHERE job_id = 'IT_PROG'
                                  )  AND  job_id<>'IT_PROG';
                      
                        # 等价于

                                  SELECT last_name,employee_id,job_id,salary
                                  FROM employees
                                  WHERE salary < (
                                            SELECT max(salary)
                                            FROM employees
                                            WHERE job_id = 'IT_PROG'
                                  )  AND  job_id<>'IT_PROG';

                      案例3:返回其它部门中比job_id为‘IT_PROG’部门所有工资都低的员工   的员工号、姓名、job_id 以及salary

                                 SELECT last_name,employee_id,job_id,salary
                                 FROM employees
                                 WHERE salary<ALL(
                                          SELECT DISTINCT salary
                                          FROM employees
                                          WHERE job_id = 'IT_PROG'
                                 ) AND job_id<>'IT_PROG';

                          # 等价于

                                 SELECT last_name,employee_id,job_id,salary
                                 FROM employees
                                 WHERE salary < (
                                          SELECT min(salary)
                                          FROM employees
                                          WHERE job_id = 'IT_PROG'
                                 ) AND job_id<>'IT_PROG';

                 #3、行子查询(结果集为 一行多列 或者 多行多列)
                        案例:查询员工编号最小并且工资最高的员工信息
                              ①查询最小的员工编号
                                          SELECT MIN(employee_id)
                                          FROM employees

                              ②查询最高工资
                                          SELECT MAX(salary)
                                          FROM employees

                              ③查询员工信息
                                          SELECT *
                                          FROM employees
                                          WHERE employee_id=(
                                                SELECT MIN(employee_id)
                                                FROM employees
                                          )AND salary=(
                                                SELECT MAX(salary)
                                                FROM employees
                                          );

                              # 采用行子查询:
                                          SELECT * 
                                          FROM employees
                                          WHERE (employee_id,salary)=(
                                                SELECT MIN(employee_id),MAX(salary)
                                                FROM employees
                                          );



           exists后面(相关子查询):支持表子查询
                        语法:
                              exists(完整的查询语句)
                              结果:1或0

                #案例1:查询有员工的部门名

                        #in
                              SELECT department_name
                              FROM departments d
                              WHERE d.`department_id` IN(
                                      SELECT department_id
                                      FROM employees
                              );

                        #exists
                              SELECT department_name
                              FROM departments d
                              WHERE EXISTS(
                                      SELECT *
                                      FROM employees e
                                      WHERE d.`department_id`=e.`department_id`
                              );

                #案例2:查询没有女朋友的男神信息

                        #in
                              SELECT bo.*
                              FROM boys bo
                              WHERE bo.id NOT IN(
                                       SELECT boyfriend_id
                                       FROM beauty
                              );

                        #exists
                              SELECT bo.*
                              FROM boys bo
                              WHERE NOT EXISTS(
                                        SELECT boyfriend_id
                                        FROM beauty b
                                        WHERE bo.`id`=b.`boyfriend_id`
                              );
        
    * 按结果集的行列数不同:
            标量子查询(结果集只有一行一列)
            列子查询(结果集只有一列多行)
            行子查询(结果集有一行多列)
            表子查询(结果集一般为多行多列)

进阶八:分页查询

   1、 应用场景:当要显示的数据,一页显示不全,需要分页提交sql请求
   2、 语法:
            select 查询列表
            from 表
            【join type join 表2
            on 连接条件
            where 筛选条件
            group by 分组字段
            having 分组后的筛选
            order by 排序的字段】
            limit 【offset,】size;

      *  offset要显示条目的起始索引(起始索引从0开始)
      *  size 要显示的条目个数
    
  3、特点:
        ①limit语句放在查询语句的最后
        ②公式: limit (page-1)*size,size;   【要显示的页数 page,每页的条目数size】

                select 查询列表
                from 表
                limit (page-1)*size,size;
      
         #案例1:查询前五条员工信息
                  SELECT * FROM  employees LIMIT 0,5;
                  SELECT * FROM  employees LIMIT 5;

         #案例2:查询第11条——第25条
                  SELECT * FROM  employees LIMIT 10,15;

         #案例3:有奖金的员工信息,并且工资较高的前10名显示出来
                  SELECT   *  FROM  employees 
                  WHERE commission_pct IS NOT NULL 
                  ORDER BY salary DESC 
                  LIMIT 10 ;

进阶九:联合查询

1、union 联合 合并:将多条查询语句的结果合并成一个结果

2、语法:
                查询语句1
                union
                查询语句2
                union
                ...
3、应用场景:
          要查询的结果来自于多个表,且多个表没有直接的连接关系,但查询的信息一致时

4、特点:
      ① 、要求多条查询语句的查询列数是一致的!
      ② 、要求多条查询语句的查询的每一列的类型和顺序最好一致
      ③ 、union关键字默认去重,如果使用union all 可以包含重复项

    #引入的案例:查询部门编号>90或邮箱包含a的员工信息

        SELECT * FROM employees WHERE email LIKE '%a%' OR department_id>90;;

        SELECT * FROM employees  WHERE email LIKE '%a%'
        UNION
        SELECT * FROM employees  WHERE department_id>90;


    #案例:查询中国用户中男性的信息以及外国用户中年男性的用户信息

          SELECT id,cname FROM t_ca WHERE csex='男'
          UNION ALL
          SELECT t_id,tname FROM t_ua WHERE tGender='male';

DML语言的学习

DML (数据操作语言):
      插入:insert
      修改:update
      删除:delete

一、插入语句
      方式一:经典的插入
           1、 语法:
                   insert into 表名(列名,...) values(值1,...);
           2、特点:
                ①、字段类型和值类型必须一致或兼容,而且要一一对应
                ②、可以为空的字段,可以不用插入值,或用null填充;不可以为空的字段,必须插入值
                ③、列的顺序可以调换,但必须一一对应
                ④、字段个数和值的个数必须一致
                ⑤、列名可以省略,但默认所有列名的顺序和表中的存储顺序一致

      方式二:
           1、 语法:
                   insert into 表名 set 列名=值,列名=值,... ;
        
       两种方式大pk 
              #1、方式一支持插入多行,方式二不支持

                  INSERT INTO beauty
                  VALUES(23,'唐艺昕1','女','1990-4-23','1898888888',NULL,2),
                  (24,'唐艺昕2','女','1990-4-23','1898888888',NULL,2),
                  (25,'唐艺昕3','女','1990-4-23','1898888888',NULL,2);

              #2、方式一支持子查询,方式二不支持

                   INSERT INTO beauty(id,NAME,phone)
                   SELECT 26,'宋茜','11809866';
                或
                   INSERT INTO beauty(id,NAME,phone)
                   SELECT id,boyname,'1234567'
                   FROM boys WHERE id<3;

二、修改语句
      1、修改单表的记录

                语法:
                        update 表名
                        set 列=新值,列=新值,...
                        where 筛选条件;

      2、修改多表的记录【补充】
             sql92语法:
                              update 表1 别名,表2 别名
                              set 列=值,...
                              where 连接条件
                              and 筛选条件;

             sql99语法:
                              update 表1 别名
                              inner|left|right join 表2 别名
                              on 连接条件
                              set 列=值,...
                              where 筛选条件;

                #案例2:修改没有男朋友的女神的男朋友编号都为2号
                        UPDATE boys bo
                        RIGHT JOIN beauty b ON bo.`id`=b.`boyfriend_id`
                        SET b.`boyfriend_id`=2
                        WHERE bo.`id` IS NULL;

三、删除语句
        方式一:delete
               语法:
                      1、单表的删除【】
                             delete from 表名 where 筛选条件 【limit 条目数】

                      2、多表的删除【补充】
                        sql92语法:
                                 delete 表1的别名,表2的别名
                                 from 表1 别名,表2 别名
                                 where 连接条件
                                 and 筛选条件;

                        sql99语法:

                                 delete 表1的别名,表2的别名【要删除哪个表,就写哪个表的别名】
                                 from 表1 别名
                                 inner|left|right join 表2 别名 on 连接条件
                                 where 筛选条件;

                         #案例:删除张无忌的女朋友的信息

                                  DELETE b
                                  FROM beauty b
                                  INNER JOIN boys bo ON b.`boyfriend_id` = bo.`id`
                                  WHERE bo.`boyName`='张无忌';

                          #案例:删除黄晓明的信息以及他女朋友的信息
                                  DELETE b,bo
                                  FROM beauty b
                                  INNER JOIN boys bo ON b.`boyfriend_id`=bo.`id`
                                  WHERE bo.`boyName`='黄晓明';

        方式二:truncate
                语法:
                    truncate table 表名;  【不可以加where 条件】


        * delete pk truncate【面试题】
              1.delete 可以加筛选[where] 条件,truncate不能加where 条件
              2.truncate删除,效率高一丢丢
              3.假如要删除的表中有自增长列,
                如果用delete删除后,再插入数据,自增长列的值从断点开始,
                而truncate删除后,再插入数据,自增长列的值从1开始。
              4.truncate删除没有返回值,delete删除有返回值,返回受影响的行数
              5.truncate删除不能回滚,delete删除可以回滚.

DDL语言的学习

DDL(数据定义语言):用于库和表的管理
        *  库的管理:创建(create)、修改(alter)、删除(drop)
        *  表的管理:创建(create)、修改(alter)、删除(drop)

 一、库的管理
       1、库的创建
            (1)、第一种写法:
                    create [if not exists]  database   数据库名;
            (2)、第二种写法:
                     create [if not exists]  database  数据库名  default  character   set  编码集;
            (3)、第三种写法:
                     create  [if not exists]  database  数据库名 default  character  set   编码集  COLLATE  校验集;

           例如:
              create  database mysql1;
              create database  mysql2 character set utf8;      //指定字符集
              create database mys1l3  character set utf8  collate utf8_general_ci;    //指定字符集和校验集
        
      2、库名的修改【以前可以使用,现在不可以,因为可能导致库中数据的丢失】
            RENAME DATABASE books TO 新库名;

      3、修改数据库(了解):
              (1)、修改数据库的编码与校验集:
                     alter database  数据库名  character set  字符编码集  collate  校验集;
              (2)、切换数据库:
                     use 数据库名;
              (3)、查看当前所使用的数据库:
                     select database();

      4、库的删除
            DROP DATABASE IF EXISTS 数据库名;

      5、查看数据库:
            show databases;            //查看数据库服务器下的所有数据库

      6、显示数据库的创建语句:
            show create database  数据库名;      //可以看到数据库创建时指定的相关信息

二、表的管理
      1.表的创建 
          语法:
              create table 表名(
                  列名 列的类型【(长度) 约束】,
                  列名 列的类型【(长度) 约束】,
                  列名 列的类型【(长度) 约束】,
                  ...
                  列名 列的类型【(长度) 约束】
              )engine=引擎名 default charset=字符集;

        #案例:创建表user

          create table user(           #规范的创建SQL语句
                id int(3) primary key auto_increment,    #int(3)中的3和tinyint(1)中的1代表的宽度而不是长度
                account varchar(22) not null default '', 
                password varchar(100) not null default '',
                create_time datetime not null default current_timestamp,
                update_time datetime not null default current_timestamp on update current_timestamp,
                record_status tinyint(1) not null default 1
          ) engine=innoDB default charset=utf8;             #创建引擎和默认编码

      2.表的修改
           语法:
                alter table 表名 add|drop|modify|change column 列名 【列类型 约束】;

            ①、修改列名
                ALTER TABLE 表名 CHANGE COLUMN 旧列名  新列名 列类型;

            ②、修改列的类型或约束
                ALTER TABLE 表名 MODIFY COLUMN 列名 列类型;

            ③、添加新列
                ALTER TABLE 表名 ADD COLUMN 列名 列类型  【first | after  字段名】;   【添加到表的前面第一个字段或者指定字段名的后面 】

            ④、删除列
                ALTER TABLE 表名 DROP COLUMN  列名 ;

            ⑤、修改表名
                ALTER TABLE 表名  RENAME 【TO】 新表名;

            ⑥、修改表的字符集
                ALTER TABLE 表名 CONVERT TO CHARACTER SET 字符集 COLLATE 校验集;

            ⑦、修改字段的字符集
                ALTER TABLE 表名 CHANGE 字段名 字段名 该字段原来的数据类型 CHARACTER SET 字符集 COLLATE 校验集;

      3.表的删除
           语法:
                DROP TABLE 【IF EXISTS 】 表名;

        #通用的写法:
                DROP DATABASE IF EXISTS 旧库名;
                CREATE DATABASE 新库名;

                DROP TABLE IF EXISTS 旧表名;
                CREATE TABLE  表名();

      4.表的复制
          ①、仅仅复制表的结构
                  CREATE TABLE 要创建的表名 LIKE  已存在的表名;

          ②、复制表的结构+数据
                  CREATE TABLE 要创建的表名  SELECT * FROM 已存在的表名;

          ③、只复制部分数据
                  CREATE TABLE 要创建的表名 
                  SELECT 要复制的字段  FROM  已存在的表名 WHERE  筛选条件;

          ④、仅仅复制某些字段,不要数据
                  CREATE TABLE 要创建的表名
                  SELECT 要复制的字段  FROM 已存在的表名  WHERE 筛选条件; 【如果只想复制某些字段而不想要数据,则筛选条件可以随便写一个不成立的即可,比如 0 或者 1=2 等】


 三、MySQL 创建用户并授权
     1、创建用户: 
          命令:CREATE USER 'username'@'host' IDENTIFIED BY 'password'; 

          说明:username - 你将创建的用户名, 
               host - 指定该用户在哪个主机上可以登陆,如果是本地用户可用localhost, 如果想让该用户可以从任意远程主机登陆,可以使用通配符%. 
               password - 该用户的登陆密码,密码可以为空,如果为空则该用户可以不需要密码登陆服务器. 

        例子: CREATE USER 'dog'@'localhost' IDENTIFIED BY '123456'; 
             CREATE USER 'pig'@'192.168.1.101_' IDENDIFIED BY '123456'; 
             CREATE USER 'pig'@'%' IDENTIFIED BY '123456'; 
             CREATE USER 'pig'@'%' IDENTIFIED BY ''; 
             CREATE USER 'pig'@'%'; 


    2、授权: 
          命令:GRANT privileges ON databasename.tablename TO 'username'@'host' 

          说明: privileges - 用户的操作权限,如SELECT , INSERT , UPDATE 等.如果要授予所的权限则使用ALL.;
                databasename - 数据库名,
                tablename-表名,如果要授予该用户对所有数据库和表的相应操作权限则可用*表示, 如*.*. 

          例子: GRANT SELECT, INSERT ON test.user TO 'pig'@'%'; 
                   GRANT ALL ON *.* TO 'pig'@'%'; 

      【注意:】用以上命令授权的用户不能给其它用户授权,如果想让该用户可以授权,用以下命令: 
            GRANT privileges ON databasename.tablename TO 'username'@'host' WITH GRANT OPTION; 

           *  授权的数据库不要用mysql自带的数据库,否则不起作用。

    3、设置与更改用户密码 
          命令:SET PASSWORD FOR 'username'@'host' = PASSWORD('newpassword');
               如果是当前登陆用户用SET PASSWORD = PASSWORD("newpassword"); 

          例子: SET PASSWORD FOR 'pig'@'%' = PASSWORD("123456"); 

    4、撤销用户权限 
            命令: REVOKE privilege ON databasename.tablename FROM 'username'@'host'; 

            例子: REVOKE SELECT ON *.* FROM 'pig'@'%'; 

            【注意】: 假如你在给用户'pig'@'%'授权的时候是这样的(或类似的):
                     GRANT SELECT ON test.user TO 'pig'@'%', 则在使用REVOKE SELECT ON *.* FROM 'pig'@'%';命令并不能撤销该用户对test数据库中user表的SELECT 操作.
                     相反,如果授权使用的是GRANT SELECT ON *.* TO 'pig'@'%';则REVOKE SELECT ON test.user FROM 'pig'@'%';命令也不能撤销该用户对test数据库中user表的Select 权限. 

            具体信息可以用命令SHOW GRANTS FOR 'pig'@'%'; 查看. 

    5、删除用户 
          命令: DROP USER 'username'@'host'; 

MySQL中支持emoji表情的存储

  正常使用uft-8方式存储是不能存储emoji表情文字的,主要原因是utf8编码的一个字符最多3个字节,但是一个emoji表情为4个字节,所以utf8不支持存储emoji表情。
  但是utf8的超集utf8mb4一个字符最多能有4字节,所以能支持emoji表情的存储。下面说说具体操作步骤:

  1、需要你的mysql数据库版本在5.5以上;

  2、更改你的数据库,表,以及需要存储emoji列的编码方式为utf8mb4 ;
        
       # 对每一个数据库:
            ALTER DATABASE 数据库名字 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci;

       # 对每一个表:
            ALTER TABLE 表名字 CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

       # 对存储emoji表情的字段:
            ALTER TABLE 表名字 CHANGE 字段名字 字段名字 该字段的类型 CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

         【注意】:utf8mb4完全向后兼容utf8,无乱码或其他数据丢失的形式出现。理论上是可以放心修改,如果不放心修改,可以备份数据

  3、修改my.ini数据库配置【Linux系统中的配置文件为my.cnf,Winows中的配置文件为my.ini】
        [client]
        default-character-set = utf8mb4

        [mysqld]
        character-set-client-handshake = FALSE
        character-set-server = utf8mb4
        collation-server = utf8mb4_unicode_ci
        init_connect=’SET NAMES utf8mb4'

        [mysql]
        default-character-set = utf8mb4

         修改完成成,wq保存并退出

  4、重启mysql
        如果使用 service mysql restart,最后发现这条命令并不管用,重启没有成功,导致后面查看字符集的时候,并没有达到想要的字符集的状态时,可以采用下面的方法才可以正确的重启mysql:

         ①、停止msql的运行
                  通过/etc/init.d/mysql执行stop命令

         ②、启动mysql
                  通过/etc/init.d/mysql执行start命令

  5、检查字符集:
        进入mysql中,用
                SHOW VARIABLES WHERE Variable_name LIKE 'character\_set\_%' ;
        OR 
                Variable_name LIKE 'collation%';       命令查看字符集的情况

  6、确认mysql驱动、连接串:

    ①、确保mysql connection版本高于5.1.13,否则仍然不能使用utf8mb4

    ②、确认服务器端的db配置文件中的字符集是否修改过来?
             jdbc.driverClassName=com.mysql.jdbc.Driver         
             jdbc.url=jdbc:mysql://主机名:端口/数据库?useUnicode=true&characterEncoding=utf8mb4&autoReconnect=true&rewriteBatchedStatements=TRUE

   7、带有emoji表情的sql文件的导入与导出(主要为windows中的导出)           
        ①、导出
            在进行把后缀名为.sql的文件,且文件数据中包含emoji表情的数据,进行备份导出的时候,此时不要使用第三方软件进行导出,而是使用命令行的形式执行该导出动作,
            其主要原因是使用第三方导出该文件时,由于其默认的导出的编码格式为utf-8,该编码格式最多只支持3个字节,而一个emoji表情有4个字节,这将导致emoji表情的数据变成乱码。
            所以在本地导出的时候具体操作步骤如下:

                *  打开cmd,先找到mysqldump这个执行文件所在的路径【即mysql安装的bin目录】;

                *  在路径后输入mysqldump –default-character-set-utf8mb4  –u  用户名  –p  数据库名 > 导出该文件的物理路径,按“Enter”,即可完成导出功能,在导出的物理路径中即可找到已被导出的该文件。

        ②、导入
               *  执行 mysql -u 用户名 -h 主机名 -P 端口号 -p密码 进入mysql数据库;
               *  创建要导入sql的数据库  create database 数据库名;
               *  use 上一步创建号的数据库名;
               *  source 要导入的sql文件全路径

常见的数据类型

一、数值型:
    * 整型:
        ①、分类:
               类型     tinyint、smallint、mediumint、int/integer、bigint
               字节数       1       2        3          4          8

        ②、特点:
            1、如果不设置无符号还是有符号,默认是有符号,如果想设置无符号,需要添加unsigned关键字
            2、如果插入的数值超出了整型的范围,会报out of range异常,并且插入的是临界值
            3、如果不设置长度,会有默认的长度,长度代表了显示结果中该列的最大宽度,如果不够会用0在左边填充,但必须搭配zerofill使用才会使用0在左边填充
              【对于整型,它的范围是由前面类型决定的】
            4、如果使用了zerofill 关键字,则默认就是无符号的,所以无需添加unsigned 关键字

   * 小数:
         1、分类
             ①、 定点数
                  dec(M,D)
                  decimal(M,D)
             ②、浮点数
                  float(M,D)
                  double(M,D)

        2、特点:
            ①、M:整数部位+小数部位 一共有M位
               D:小数部位的位数
               如果超过范围,则插入临界值

            ②、M和D都可以省略
               如果是decimal,则M默认为10,D默认为0
               如果是float和double,则会根据插入的数值的精度来决定精度

            ③、定点型的精确度较高,如果要求插入数值的精度较高,如货币运算等则考虑使用

        #原则:
            所选择的类型越简单越好,能保存数值的类型越小越好


二、字符型:
    1、分类:
          较短的文本:char、varchar

            其它还有:
                  binary和varbinary用于保存较短的二进制
                  enum用于保存枚举
                  set用于保存集合

          较长的文本:text、blob(较长的二进制数据)

          举例:
             ①、枚举:
                CREATE TABLE tab_char(
                      c1 ENUM('a','b','c')
                );

                INSERT INTO tab_char VALUES('a');          正确
                INSERT INTO tab_char VALUES('b');          正确
                INSERT INTO tab_char VALUES('c');          正确
                INSERT INTO tab_char VALUES('m');         为空【因为不包含在枚举中,所以为空】
                INSERT INTO tab_char VALUES('A');         正确 【插入的为a,不区分大小写】

              ②、集合:
                CREATE TABLE tab_set(
                      s1 SET('a','b','c','d')
                );

                INSERT INTO tab_set VALUES('a,A');           显示 a  【唯一,不重复】
                INSERT INTO tab_set VALUES('d,A,B');        不区分大小写,显示 a,b,d  【排序】
                INSERT INTO tab_set VALUES('g');               集合中没有,显示空
                INSERT INTO tab_set VALUES('b,c,g');         显示 b,c 【集合中有则显示,没有则不显示】

    2、特点:
                  写法                    M的意思                      特点              空间的耗费         效率
    char         char(M)          最大的字符数,可以省略,默认为1      固定长度的字符         比较耗费           高

    varchar     varchar(M)        最大的字符数,不可以省略            可变长度的字符         比较节省           低

    3、说明:char(M) 和 varchar(M) 中的 M 表示可以存储的最大字符数,如果超过了这个数,则会从左边进行截取,截取长度为M。【因为表示的是字符数,所以一个汉字,一个字母都算一个字符】  


三、日期型:
     1、分类:
          date(4个字节):只保存日期
          time (3个字节):只保存时间
          year(1个字节):只保存年
          datetime:保存日期+时间
          timestamp:保存日期+时间

    2、特点:
                              字节                范围                      时区等的影响
            datetime           8                1000——9999                      不受
            timestamp          4                1970-2038                        受


      示例:
        查看时区:
            SHOW VARIABLES LIKE 'time_zone';
        设置时区:
            SET time_zone='+9:00';

常见约束

一、含义:一种限制,用于限制表中的数据,为了保证表中的数据的准确和可靠性

二、分类:六大约束
      1、NOT NULL:非空,用于保证该字段的值不能为空
                   比如姓名、学号等

      2、DEFAULT: 默认,用于保证该字段有默认值
                  比如性别

      3、PRIMARY KEY: 主键,用于保证该字段的值具有唯一性,并且非空
                      比如学号、员工编号等

      4、UNIQUE: 唯一,用于保证该字段的值具有唯一性,可以为空
                 比如座位号

      5、CHECK: 检查约束【mysql中不支持,即添加上不报错,但是没有效果】
                比如年龄、性别

      6、FOREIGN KEY: 外键,用于限制两个表的关系,用于保证该字段的值必须来自于主表的关联列的值 【在从表添加外键约束,用于引用主表中某列的值】
                      比如学生表的专业编号,员工表的部门编号,员工表的工种编号


三、添加约束的时机:
      1.创建表时添加约束

      2.修改表时添加约束

四、约束的添加分类:
      1、列级约束: 
              六大约束语法上都支持,但外键约束和检查约束不支持,即添加上也没有效果

            ①、语法:
                   直接在字段名和类型后面追加 约束类型即可。列级约束可以在一个字段后面添加多个,中间用空格隔开,没有顺序要求。

            ②、只支持:默认、非空、主键、唯一 
              【注意:语法上六大约束都支持,但是外键和检查不支持,即添加上没有效果】

                CREATE TABLE stuinfo(
                      id INT PRIMARY KEY,  #主键
                      stuName VARCHAR(20) NOT NULL,    #非空
                      gender CHAR(1) CHECK(gender='男' OR gender ='女'),    #检查
                      seat INT UNIQUE,    #唯一
                      age INT DEFAULT  18,    #默认约束
                      majorId INT REFERENCES major(id)    #外键
                );


                CREATE TABLE major(
                      id INT PRIMARY KEY,
                      majorName VARCHAR(20)
                );

                #查看stuinfo中的所有索引,包括主键、外键、唯一以及自己创建的索引
                      SHOW INDEX FROM stuinfo;

    
      2、表级约束:
            语法上不支持非空、默认,其他的都支持,但是检查语法支持,实际添加上也没有作用
    
            ①、语法:在各个字段的最下面添加 【constraint 约束名】 约束类型(字段名) 

                    CREATE TABLE stuinfo(
                          id INT,
                          stuname VARCHAR(20),
                          gender CHAR(1),
                          seat INT,
                          age INT,
                          majorid INT,

                          CONSTRAINT pk PRIMARY KEY(id),    #主键  
                           # 【1、对于主键,就算起了名字pk,也是没有效果的,因为mysql默认主键的名字为primary
                           #   2、列级约束是没有办法给约束起名字的,只有表级约束才可以】
                          CONSTRAINT uq UNIQUE(seat),      #唯一键
                          CONSTRAINT ck CHECK(gender ='男' OR gender  = '女'),    #检查
                          CONSTRAINT fk_stuinfo_major FOREIGN KEY(majorid) REFERENCES major(id)    #外键
                    );

              #通用的写法:

                     CREATE TABLE IF NOT EXISTS stuinfo(
                              id INT PRIMARY KEY,     #主键
                              stuname VARCHAR(20) NOT NULL,  #非空
                              sex CHAR(1),
                              age INT DEFAULT 18,    #默认约束
                              seat INT UNIQUE,      #唯一键
                              majorid INT,  
                              CONSTRAINT fk_stuinfo_major FOREIGN KEY(majorid) REFERENCES major(id)     #外键
                    );


          #【注意】
                                         支持类型                          可以起约束名
           列级约束                       除了外键                             不可以
           表级约束                     除了非空和默认                           可以


五、主键和唯一的大对比:

                      保证唯一性      是否允许为空        一个表中可以有多少个       是否允许组合
            主键          √               ×                  至多有1个           √,但不推荐
            唯一          √               √                  可以有多个          √,但不推荐

【注意】
           ①、因为主键和唯一是保证唯一性的,所以设置了主键和唯一约束的字段值只能有一个,不能重复,包括null值,也只允许出现一个;
           ②、主键和唯一约束都允许组合使用,意思是可以设置多个字段组合为主键,如果设置了之后,只有设置的多个字段同时值相同才会看作是重复,才会起作用,单个字段是可以重复的,但是不可以为空
              CONSTRAINT pk PRIMARY KEY(id, stuname...),    #主键
              CONSTRAINT uq UNIQUE(seat, seat2,....),      #唯一键

六、外键:
      1、要求在从表设置外键关系
      2、从表的外键列的类型和主表的关联列的类型要求一致或兼容,名称无要求
      3、主表的关联列必须是一个key(一般是主键或唯一)
      4、插入数据时,先插入主表,再插入从表
         删除数据时,先删除从表,再删除主表

      5、一个字段可以设置多个约束类型,中间用空格隔开
                例如:stuname VARCHAR(20) NOT NULL  UNIQUE  ... ,  #非空  #唯一  ...

  # 可以通过以下两种方式删除主表的记录:
        方式一:级联删除
            ALTER  TABLE 表名 ADD constraint  外键约束名  foreign key(从表字段)  references  主表(字段) ON   DELETE CASCADE;

        方式二:级联置空
            ALTER  TABLE 表名 ADD constraint  外键约束名  foreign key(从表字段)  references  主表(字段) ON   DELETE set null;

七、修改表时添加约束
      1、添加列级约束
            alter table 表名 modify column 字段名 字段类型 新约束;

      2、添加表级约束
            alter table 表名 add 【constraint 约束名】 约束类型(字段名) 【外键的引用】;

       举例:      
            #1.添加非空约束
                  ALTER TABLE stuinfo MODIFY COLUMN stuname VARCHAR(20)  NOT NULL;
            #2.添加默认约束
                  ALTER TABLE stuinfo MODIFY COLUMN age INT DEFAULT 18;
            #3.添加主键
                  #①列级约束
                          ALTER TABLE stuinfo MODIFY COLUMN id INT PRIMARY KEY;
                  #②表级约束
                          ALTER TABLE stuinfo ADD PRIMARY KEY(id);

            #4.添加唯一
                  #①列级约束
                          ALTER TABLE stuinfo MODIFY COLUMN seat INT UNIQUE;
                  #②表级约束
                          ALTER TABLE stuinfo ADD UNIQUE(seat);

            #5.添加外键
                  ALTER TABLE stuinfo ADD CONSTRAINT fk_stuinfo_major FOREIGN KEY(majorid) REFERENCES major(id); 


八、修改表时删除约束

        #1.删除非空约束
              ALTER TABLE stuinfo MODIFY COLUMN stuname VARCHAR(20) NULL;

        #2.删除默认约束
              ALTER TABLE stuinfo MODIFY COLUMN age INT ;

        #3.删除主键
              ALTER TABLE stuinfo DROP PRIMARY KEY;

        #4.删除唯一
              ALTER TABLE stuinfo DROP INDEX seat;

        #5.删除外键
              ALTER TABLE stuinfo DROP FOREIGN KEY fk_stuinfo_major;



                    位置                    支持的约束类型   (检查约束除外)             是否可以起约束名
    列级约束:     列的后面                    语法都支持,但外键没有效果                      不可以
    表级约束:     所有列的下面                 默认和非空不支持,其他支持                 可以(主键没有效果)     

标识列 [AUTO_INCREMENT]

1、标识列:又称为自增长列, 可以不用手动的插入值, 系统提供默认的序列值, 初始默认值为1, 即从1开始自增

2、特点:
      ①、标识列必须和主键搭配吗?   不一定,但要求是一个key

      ②、一个表可以有几个标识列?   至多一个!

      ③、标识列的类型只能是数值型(整型、浮点型)

      ④、标识列可以通过 SET auto_increment_increment=3;设置步长
         MySQL 不可以通过: SET auto_increment_offset=3;  修改起始值,即使设置了,也不会有效果,但是可以通过 手动插入值,设置起始值【第一条数据可以手动插入你想要的起始值,后面无需再添加,就会自动从你插入的起始值自增】

      #查看自增长列相关的设置【有起始值和步长,默认都是1】
        SHOW VARIABLES LIKE '%auto_increment%';

3、修改表时设置自增长列        
           ALTER TABLE 表名 MODIFY COLUMN 字段名 字段类型  约束  AUTO_INCREMENT;

   删除自增长列
           ALTER TABLE 表名 MODIFY COLUMN 字段名 字段类型 ;

事务

1、TCL语言:Transaction Control Language 事务控制语言

2、事务:一个或一组sql语句组成一个执行单元,这个执行单元要么全部执行,要么全部不执行。

        案例:转账

3、事务的特性:ACID
        原子性:一个事务不可再分割,要么都执行要么都不执行
        一致性:一个事务执行会使数据从一个一致状态切换到另外一个一致状态
        隔离性:一个事务的执行不受其他事务的干扰
        持久性:一个事务一旦提交,则会永久的改变数据库的数据.

4、事务的创建
      ①、隐式事务:事务没有明显的开启和结束的标记
                  比如insert、update、delete语句

      ②、显式事务:事务具有明显的开启和结束的标记
                 前提:必须先设置自动提交功能为禁用    set autocommit=0;


      查看变量: SHOW VARIABLES LIKE 'autocommit';    MySQL默认为ON,开启自动提交(即隐式事务)

5、使用事务的步骤:
      步骤1:开启事务
              set autocommit=0;
              start transaction;可选的
   
      步骤2:编写事务中的sql语句(select insert update delete)
              语句1;
              语句2;
              ...

      步骤3:结束事务
              commit;提交事务
              rollback;回滚事务

6、事务的隔离级别:

     对于同时运行的多个事务, 当这些事务访问数据库中相同的数据时, 如果没有采取必要的隔离机制, 就会导致各种并发问题:
         脏读: 对于两个事务 T1, T2, T1 读取了已经被 T2 更新但还没有被提交的字段之后, 若 T2 回滚, T1读取的内容就是临时且无效的.
         不可重复读: 对于两个事务T1, T2, T1 读取了一个字段, 然后 T2 更新了该字段. 之后, T1再次读取同一个字段, 值就不同了.
         幻读: 对于两个事务T1, T2, T1 从一个表中读取了一个字段, 然后 T2 在该表中插入了一些新的行. 之后, 如果 T1 再次读取同一个表, 就会多出几行


                                  脏读        不可重复读     幻读
            read uncommitted:      √            √           √
            read committed:        ×            √           √
            repeatable read:       ×            ×           √
            serializable:          ×            ×           ×


          ①、 Mysql 支持 4 种事务隔离级别.mysql中默认的隔离级别是 repeatable read
              Oracle 支持2 种事务隔离级别:READ COMMITED, SERIALIZABLE。默认的隔离级别是 read committed

          ②、查看隔离级别
                  select @@tx_isolation;

          ③、设置当前MYSQL的连接 / 数据库系统的全局 隔离级别
                  set session|global transaction isolation level 隔离级别;


7、savepoint 节点名:设置保存点, 只能搭配rollback 使用
            示例:只删除了id为25的,id为28的回滚了,没有删除成功
                  SET autocommit=0;
                  START TRANSACTION;
                  DELETE FROM account WHERE id=25;
                  SAVEPOINT a;    #设置保存点
                  DELETE FROM account WHERE id=28;
                  ROLLBACK TO a;  #回滚到保存点

视图

一、含义:mysql5.1版本出现的新特性,一种虚拟存在的表,行和列的数据来自定义视图的查询中使用的表,并且是在使用视图时动态生成的,
        只保存了sql逻辑,不保存查询结果

    * 应用场景:
            – 多个地方用到同样的查询结果
            – 该查询结果使用的sql语句较复杂

    * 使用视图的好处:
          • 重用sql语句
          • 简化复杂的sql操作,不必知道它的查询细节
          • 保护数据,提高安全性

二、视图与表的对比:
                    创建语法的关键字        是否实际占用物理空间          使用

        视图          create view           只是保存了sql逻辑          增删改查,只是一般不能增删改,主要用于查

         表           create table          保存了数据                增删改查

三、创建视图
      1、语法:
            create view 视图名
            as
            查询语句;

    案例:#1、查询各部门的平均工资级别
            #①创建视图查看每个部门的平均工资
                  CREATE VIEW myv2
                  AS
                  SELECT AVG(salary) ag,department_id
                  FROM employees
                  GROUP BY department_id;

            #②使用
                  SELECT myv2.`ag`,g.grade_level
                  FROM myv2
                  JOIN job_grades g
                  ON myv2.`ag` BETWEEN g.`lowest_sal` AND g.`highest_sal`;

        #2、查询平均工资最低的部门名和工资

                  CREATE VIEW myv3
                  AS
                  SELECT * FROM myv2 ORDER BY ag LIMIT 1;

                  SELECT d.*,m.ag
                  FROM myv3 m
                  JOIN departments d
                  ON m.`department_id`=d.`department_id`;

四、修改视图
      方式一:
            create or replace view  视图名
            as
            查询语句;

        示例:     CREATE OR REPLACE VIEW myv3
                  AS
                  SELECT AVG(salary),job_id
                  FROM employees
                  GROUP BY job_id;

      方式二:
            alter view 视图名
            as 
            查询语句;

        示例:      ALTER VIEW myv3
                   AS
                   SELECT * FROM employees;


五、删除视图
        语法:drop view 视图名,视图名,...;

        DROP VIEW emp_v1,emp_v2,myv3;

六、查看视图结构

        DESC myv3;

        SHOW CREATE VIEW myv3;     #可以查看更加详细的信息,如创建的语句,字符集等

七、视图的更新
        1.插入
              INSERT INTO myv1 VALUES('张飞','zf@qq.com');

        2.修改
              UPDATE myv1 SET last_name = '张无忌' WHERE last_name='张飞';

        3.删除
              DELETE FROM myv1 WHERE last_name = '张无忌';

    #具备以下特点的视图不允许更新
        ①包含以下关键字的sql语句:分组函数、distinct、group  by、having、union或者union all
        
        ②常量视图
                CREATE OR REPLACE VIEW myv2
                AS
                SELECT 'john' NAME;

                #查看
                SELECT * FROM myv2;

                #更新
                UPDATE myv2 SET NAME='lucy';     #不能更新

        ③Select中包含子查询
  
        ④join

        ⑤from一个不能更新的视图
                  CREATE OR REPLACE VIEW myv5
                  AS
                  SELECT * FROM myv3;     #myv3视图不能更新

        ⑥where子句的子查询引用了from子句中的表
                  CREATE OR REPLACE VIEW myv6
                  AS
                  SELECT last_name,email,salary
                  FROM employees
                  WHERE employee_id IN(
                        SELECT  manager_id
                        FROM employees
                        WHERE manager_id IS NOT NULL
                  );

变量

一、分类:  
    * 系统变量:
          全局变量
          会话变量

    * 自定义变量:
          用户变量
          局部变量

二、系统变量
      说明:变量由系统定义,不是用户定义,属于服务器层面
      注意:全局变量需要添加global关键字,会话变量需要添加session关键字,如果不写,默认会话级别
  
    ①、使用步骤:
        1、查看所有系统变量
            show global|【session】variables;

        2、查看满足条件的部分系统变量
            show global|【session】 variables like '%char%';

        3、查看指定的系统变量的值
            select @@global.系统变量名;            --->全局的
            select @@系统变量名;                   --->会话的

        4、为某个系统变量赋值
              方式一:
                  set global|【session】  系统变量名 = 值;
              方式二:
                  set @@global|session.系统变量名 = 值;

    、全局变量
        作用域:针对于所有会话(连接)有效,但不能跨重启

        ①、查看所有全局变量
            SHOW GLOBAL VARIABLES;
        
        ②、查看满足条件的部分系统变量
            SHOW GLOBAL VARIABLES LIKE '%char%';

        ③、查看指定的系统变量的值
            SELECT @@global.autocommit;

        ④、为某个系统变量赋值
            SET @@global.autocommit=0;   或    SET GLOBAL autocommit=0;

    、会话变量
        作用域:针对于当前会话(连接)有效

        ①、查看所有会话变量
            SHOW SESSION VARIABLES;

        ②、查看满足条件的部分会话变量
            SHOW SESSION VARIABLES LIKE '%char%';

        ③、查看指定的会话变量的值
            SELECT @@autocommit;    或    SELECT @@session.tx_isolation;

        ④、为某个会话变量赋值
              SET @@session.tx_isolation='read-uncommitted';   或     SET SESSION tx_isolation='read-committed';

三、自定义变量
      说明:变量由用户自定义,而不是系统提供的

      ①、使用步骤:
          1、声明
          2、赋值
          3、使用(查看、比较、运算等)

      、用户变量  
            1、作用域:针对于当前会话(连接)有效,作用域同于会话变量,可以放在任何地方【begin  end里面或者外面都可以】。
            2、使用步骤:【赋值操作符:  = 或 :=】

                ①声明并初始化
                      SET @变量名=值;
                      SET @变量名:=值;
                      SELECT @变量名:=值;

                ②赋值(更新变量的值)
                      #方式一:通过set 或 select 
                              SET @变量名=值;
                              SET @变量名:=值;
                              SELECT @变量名:=值;
                      #方式二:通过select into
                              SELECT 字段 INTO @变量名
                              FROM 表;

                 ③使用(查看变量的值)
                      SELECT @变量名;


       、局部变量
            1、作用域:仅仅在定义它的begin end块中有效, 必须应用在 begin end中的第一句话
            2、使用步骤:

                 ①声明
                        DECLARE 变量名 类型;
                        DECLARE 变量名 类型 【DEFAULT 值】;

                 ②赋值(更新变量的值)
                        #方式一:
                              SET 局部变量名=值;
                              SET 局部变量名:=值;
                              SELECT @局部变量名:=值;
                        #方式二:
                              SELECT 字段 INTO 局部变量名
                              FROM 表;

                  ③使用(查看变量的值)
                         SELECT 局部变量名;


            #案例:声明两个变量,求和并打印
                  #用户变量
                         SET @m=1;
                         SET @n=1;
                         SET @sum=@m+@n;
                         SELECT @sum;

                  #局部变量
                         DECLARE m INT DEFAULT 1;
                         DECLARE n INT DEFAULT 1;
                         DECLARE SUM INT;
                         SET SUM=m+n;
                         SELECT SUM;


   、 用户变量和局部变量的对比
                            作用域               定义位置                          语法
            用户变量        当前会话              会话的任何地方               必须加@符号,不用指定类型
            局部变量        定义它的BEGIN END中    BEGIN END中的第一句话        一般不用加@,需要指定类型

存储过程和函数

一、存储过程和函数:类似于java中的方法
二、好处:
        1、提高代码的重用性
        2、简化操作


、存储过程
    一、含义:一组预先编译好的SQL语句的集合,理解成批处理语句
    二、好处:
        1、提高代码的重用性
        2、简化操作
        3、减少了编译次数并且减少了和数据库服务器的连接次数,提高了效率

    三、创建语法
          CREATE PROCEDURE 存储过程名(参数列表)
          BEGIN
            存储过程体(一组合法的SQL语句)
          END

      #注意:
          1、参数列表包含三部分:参数模式  参数名  参数类型
             举例:
              in stuname varchar(20)

            参数模式:
                  in:该参数可以作为输入,也就是该参数需要调用方传入值
                  out:该参数可以作为输出,也就是该参数可以作为返回值
                  inout:该参数既可以作为输入又可以作为输出,也就是该参数既需要传入值,又可以返回值

          2、如果存储过程体仅仅只有一句话,begin end可以省略
             存储过程体中的每条sql语句的结尾要求必须加分号。
             存储过程的结尾可以使用 delimiter 重新设置

             语法:
                  delimiter 结束标记

             案例:
                      delimiter $

    四、调用语法
          CALL 存储过程名(实参列表);

#--------------------------------案例演示-----------------------------------
* 1、空参列表

    #案例:插入到admin表中五条记录
        DELIMITER $
        CREATE PROCEDURE myp1()
        BEGIN
                INSERT INTO admin(username,`password`) 
                VALUES('john1','0000'),('lily','0000'),('rose','0000'),('jack','0000'),('tom','0000');
        END $

    #调用
        CALL myp1()$

* 2、创建带in模式参数的存储过程

    #案例1:创建存储过程实现 根据女神名,查询对应的男神信息
        CREATE PROCEDURE myp2(IN beautyName VARCHAR(20))
        BEGIN
              SELECT bo.*
              FROM boys bo
              RIGHT JOIN beauty b ON bo.id = b.boyfriend_id
              WHERE b.name=beautyName;
        END $

    #调用
        CALL myp2('柳岩')$

    #案例2 :创建存储过程实现,用户是否登录成功
          CREATE PROCEDURE myp4(IN username VARCHAR(20),IN PASSWORD VARCHAR(20))
          BEGIN
              DECLARE result INT DEFAULT 0;    #声明并初始化

              SELECT COUNT(*) INTO result      #赋值
              FROM admin
              WHERE admin.username = username
              AND admin.password = PASSWORD;

              SELECT IF(result>0,'成功','失败');        #使用
          END $

    #调用
          CALL myp3('张飞','8888')$


* 3、创建out 模式参数的存储过程

      #案例1:根据输入的女神名,返回对应的男神名
            CREATE PROCEDURE myp6(IN beautyName VARCHAR(20),OUT boyName VARCHAR(20))
            BEGIN
                SELECT bo.boyname INTO boyname
                FROM boys bo
                RIGHT JOIN
                beauty b ON b.boyfriend_id = bo.id
                WHERE b.name=beautyName ;
            END $


      #案例2:根据输入的女神名,返回对应的男神名和魅力值
          CREATE PROCEDURE myp7(IN beautyName VARCHAR(20),OUT boyName VARCHAR(20),OUT usercp INT) 
          BEGIN
              SELECT boys.boyname ,boys.usercp INTO boyname,usercp
              FROM boys 
              RIGHT JOIN
              beauty b ON b.boyfriend_id = boys.id
              WHERE b.name=beautyName ;
          END $

      #调用
            CALL myp7('小昭',@name,@cp)$
            SELECT @name,@cp$

* 4、创建带inout模式参数的存储过程

        #案例1:传入a和b两个值,最终a和b都翻倍并返回
              CREATE PROCEDURE myp8(INOUT a INT ,INOUT b INT)
              BEGIN
                  SET a=a*2;
                  SET b=b*2;
              END $

        #调用
              SET @m=10$
              SET @n=20$
              CALL myp8(@m,@n)$
              SELECT @m,@n$

    、总结:
           ①、空参列表:调用方法 --->  call 存储过程名() 结束符
                   例如: CALL myp3()$
           ②、带in模式参数的存储过程:调用方法 --->  call 存储过程名(直接输入需要的参数) 结束符
                   例如: CALL myp3('张飞','8888')$
           ③、带out 模式参数的存储过程:调用方法 --->  call 存储过程名(自定义用户变量) 结束符
                   例如: CALL myp7('小昭',@name,@cp)$                  ----> 调用
                         SELECT @name,@cp$                            ---->查看
           ④、带inout模式参数的存储过程:调用方法 --->  call 存储过程名(定义用户变量并赋值) 结束符
                  例如:      SET @m=10$                ----> 定义用户变量并赋值      
                            SET @n=20$                ----> 定义用户变量并赋值
                            CALL myp8(@m,@n)$         ----> 调用
                            SELECT @m,@n$             ---->查看

    五、删除存储过程
          语法:drop procedure 存储过程名

          示例:  DROP PROCEDURE p1;
                 DROP PROCEDURE p2,p3;      #这种写法错误,一次只可以删除一个存储过程

    六、查看存储过程的信息
          DESC myp2;        #这种写法错误,不可以使用desc 查看
          SHOW CREATE PROCEDURE  myp2;



、函数
    一、含义:一组预先编译好的SQL语句的集合,理解成批处理语句
    
    二、好处:
          1、提高代码的重用性
          2、简化操作
          3、减少了编译次数并且减少了和数据库服务器的连接次数,提高了效率

    三、区别:
          存储过程:可以有0个返回,也可以有多个返回,适合做批量插入、批量更新
          函数:有且仅有1 个返回,适合做处理数据后返回一个结果

    四、创建语法
            CREATE FUNCTION 函数名(参数列表) RETURNS 返回类型
            BEGIN
                函数体
            END

        #注意:
            1.参数列表包含两部分:
                          参数名 参数类型

            2.函数体:肯定会有return语句,如果没有会报错
              如果return语句没有放在函数体的最后也不报错,但不建议

              写法:return 值;
          
            3.函数体中仅有一句话,则可以省略begin end

            4.使用 delimiter语句设置结束标记

    五、调用语法
              SELECT 函数名(参数列表)


      #------------------------------案例演示----------------------------
* 1、无参有返回

        #案例:返回公司的员工个数
                CREATE FUNCTION myf1() RETURNS INT
                BEGIN
                      DECLARE c INT DEFAULT 0;    #定义局部变量
                      SELECT COUNT(*) INTO c      #赋值
                      FROM employees;
                      RETURN c;
                END $

                SELECT myf1()$

* 2、有参有返回

        #案例1:根据员工名,返回它的工资
                CREATE FUNCTION myf2(empName VARCHAR(20)) RETURNS DOUBLE
                BEGIN
                      SET @sal=0;    #定义用户变量 
                      SELECT salary INTO @sal     #赋值
                      FROM employees
                      WHERE last_name = empName;

                      RETURN @sal;
                END $

                SELECT myf2('k_ing') $


        #案例2:根据部门名,返回该部门的平均工资
                CREATE FUNCTION myf3(deptName VARCHAR(20)) RETURNS DOUBLE
                BEGIN
                        DECLARE sal DOUBLE ;     #定义局部变量
                        SELECT AVG(salary) INTO sal
                        FROM employees e
                        JOIN departments d ON e.department_id = d.department_id
                        WHERE d.department_name=deptName;
                        RETURN sal;
                END $

                SELECT myf3('IT')$

    六、查看函数
              SHOW CREATE FUNCTION myf3;

    七、删除函数
              DROP FUNCTION myf3;

        #案例
              #一、创建函数,实现传入两个float,返回二者之和

                  CREATE FUNCTION test_fun1(num1 FLOAT,num2 FLOAT) RETURNS FLOAT
                  BEGIN
                          DECLARE SUM FLOAT DEFAULT 0;
                          SET SUM=num1+num2;
                          RETURN SUM;
                  END $

                  SELECT test_fun1(1,2)$

流程控制结构 【顺序、分支、循环】

流程控制结构
        顺序结构:程序从上往下依次执行
        分支结构:程序从两条或多条路径中选择一条去执行
        循环结构:程序在满足一定条件的基础上,重复执行一段代码

 一、分支结构
     1、IF 函数
            ①、功能:实现简单的双分支
            ②、语法:
                      if(表达式1,表达式2,表达式3)
               执行顺序:
                      如果表达式1成立,则if 函数返回表达式2的值,否则返回表达式3的值
            ③、应用:
                      任何地方(可以放在begin end 中,也可以放在begin end 外)

      2.case结构
            ①、情况1:类似于Java中的switch语句,一般用于实现等值判断
               语法:
                  如果作为表达式使用,则语法如下: 【注意:此情况下,可以放在begin end 中,也可以放在begin end 外】
                       case 变量|表达式|字段
                       when 要判断的值1  then 返回的值1
                       when 要判断的值2  then 返回的值2
                       ...
                       else 要返回的值n
                       end;

                  如果作为独立的语句执行,则语法如下: 【注意:此情况下,只可以放在begin end 中】
                       case 变量|表达式|字段
                       when 要判断的值1  then 语句1;
                       when 要判断的值2  then 语句2;
                       ...
                       else 要返回的语句n;
                       end case;

          ②、情况2:类似于Java中的多重if语句,一般用于实现区间判断
             语法:
                如果作为表达式使用,则语法如下: 【注意:此情况下,可以放在begin end 中,也可以放在begin end 外】
                     case 
                     when 要判断的条件1  then 返回的值1
                     when 要判断的条件2  then 返回的值2
                     ...
                     else 要返回的值n
                     end;

                如果作为独立的语句执行,则语法如下: 【注意:此情况下,只可以放在begin end 中】
                     case 
                     when 要判断的条件1  then 语句1;
                     when 要判断的条件2  then 语句2;
                     ...
                     else 要返回的语句n;
                     end case;
  
        特点:
              ①、可以作为表达式,嵌套在其它语句中使用,可以放在任何地方,begin end 中或begin end 的外面
                 可以作为独立的语句使用,只能放在begin end 中
              ②、如果when 中的值满足或条件成立,则执行对应的then 后面的语句,并且结束case
                 如果都不满足,则执行else 中的语句或值
              ③、else 可以省略,如果else 省略了,并且所有的when条件都不满足,则返回null

  #案例:创建存储过程,根据传入的成绩,来显示等级,如果传入的成绩:90-100,显示A,如果成绩80-90,显示B,如果成绩60-80,显示C,否则显示D
              CREATE PROCEDURE test_case(IN score INT)
              BEGIN 
                  CASE 
                  WHEN score >= 90 AND score <= 100 THEN SELECT 'A';
                  WHEN score >= 80 THEN SELECT 'B';
                  WHEN score >= 60 THEN SELECT 'C';
                  ELSE SELECT 'D';
                  END CASE;
              END $

              CALL test_case(90)$


      3.if结构
            ①、语法:
                  if 条件1 then 语句1;
                  elseif 条件2 then 语句2;
                  ....
                  else 语句n;  【注意,else 语句可以省略】
                  end if;
        
            ②、功能:类似于多重if

            ③、应用场景:只能应用在begin end 中



     #案例1:创建函数,实现传入成绩,如果成绩>90,返回A,如果成绩>80,返回B,如果成绩>60,返回C,否则返回D
          CREATE FUNCTION test_if(score FLOAT) RETURNS CHAR
          BEGIN
                  DECLARE ch CHAR DEFAULT 'A';
                  IF score>90 THEN SET ch='A';
                  ELSEIF score>80 THEN SET ch='B';
                  ELSEIF score>60 THEN SET ch='C';
                  ELSE SET ch='D';
                  END IF;
                  RETURN ch;    
          END $

          SELECT test_if(87)$

    #案例2:创建存储过程,如果工资<2000,则删除,如果5000>工资>2000,则涨工资1000,否则涨工资500
          CREATE PROCEDURE test_if_pro(IN sal DOUBLE)
          BEGIN
                IF sal<2000 THEN DELETE FROM employees WHERE employees.salary=sal;
                ELSEIF sal>=2000 AND sal<5000 THEN UPDATE employees SET salary=salary+1000 WHERE employees.`salary`=sal;
                ELSE UPDATE employees SET salary=salary+500 WHERE employees.`salary`=sal;
                END IF;
          END $

          CALL test_if_pro(2100)$

    #案例1:创建函数,实现传入成绩,如果成绩>90,返回A,如果成绩>80,返回B,如果成绩>60,返回C,否则返回D
          CREATE FUNCTION test_case(score FLOAT) RETURNS CHAR
          BEGIN 
                DECLARE ch CHAR DEFAULT 'A';

                CASE 
                WHEN score>90 THEN SET ch='A';
                WHEN score>80 THEN SET ch='B';
                WHEN score>60 THEN SET ch='C';
                LSE SET ch='D';
                END CASE;

                RETURN ch;
          END $

          SELECT test_case(56)$



二、循环结构
        分类:
              while、loop、repeat

        循环控制:
              iterate类似于 continue,继续,结束本次循环,继续下一次
              leave 类似于  break,跳出,结束当前所在的循环

    1、while
            ①、语法:
                    【标签:】while 循环条件 do
                          循环体;
                    end while【 标签】;

            ②、特点:先判断后执行
            ③、位置:begin end 中

    2、loop
          ①、 语法:
                  【标签:】loop
                        循环体;
                  end loop 【标签】;

            ②、特点:没有条件的死循环(可以模拟简单的死循环)
            ③、位置:begin end 中

    3、repeat
           ①、 语法:
                  【标签:】repeat
                        循环体;
                  until 结束循环的条件
                  end repeat 【标签】;

            ②、特点:先执行后判断
            ③、位置:begin end 中


  #1.没有添加循环控制语句

        #案例:批量插入,根据次数插入到admin表中多条记录
                DROP PROCEDURE pro_while1$
                CREATE PROCEDURE pro_while1(IN insertCount INT)
                BEGIN
                    DECLARE i INT DEFAULT 1;
                    WHILE i<=insertCount DO
                    INSERT INTO admin(username,`password`) VALUES(CONCAT('Rose',i),'666');
                    SET i=i+1;
                    END WHILE;
                END $

                CALL pro_while1(100)$


                /*
                    int i=1;
                    while(i<=insertcount){
                        //插入    
                        i++;
                    }
                */


#2.添加leave语句

      #案例:批量插入,根据次数插入到admin表中多条记录,如果次数>20则停止
              TRUNCATE TABLE admin$
              DROP PROCEDURE test_while1$
              CREATE PROCEDURE test_while1(IN insertCount INT)
              BEGIN
                      DECLARE i INT DEFAULT 1;
                      a:WHILE i<=insertCount DO
                          INSERT INTO admin(username,`password`) VALUES(CONCAT('xiaohua',i),'0000');
                          IF i>=20 THEN LEAVE a;
                          END IF;
                          SET i=i+1;
                      END WHILE a;
              END $

              CALL test_while1(100)$


#3.添加iterate语句

      #案例:批量插入,根据次数插入到admin表中多条记录,只插入偶数次
              TRUNCATE TABLE admin$
              DROP PROCEDURE test_while1$
              CREATE PROCEDURE test_while1(IN insertCount INT)
              BEGIN
                  DECLARE i INT DEFAULT 0;
                  a:WHILE i<=insertCount DO
                    SET i=i+1;
                    IF MOD(i,2)!=0 THEN ITERATE a;
                    END IF;
    
                    INSERT INTO admin(username,`password`) VALUES(CONCAT('xiaohua',i),'0000');
    
                  END WHILE a;
               END $

                CALL test_while1(100)$

                /*
                        int i=0;
                        while(i<=insertCount){
                              i++;
                              if(i%2==0){
                                  continue;
                              }  
                            插入  
                        }
                */

流程控制经典案例:

  一、已知表stringcontent
        其中字段:
                id 自增长
                content varchar(20)

        向该表插入指定个数的,随机的字符串

          DROP TABLE IF EXISTS stringcontent;
          CREATE TABLE stringcontent(
                id INT PRIMARY KEY AUTO_INCREMENT,
                content VARCHAR(20) 
          );

          DELIMITER $
          CREATE PROCEDURE test_randstr_insert(IN insertCount INT)
          BEGIN
                DECLARE i INT DEFAULT 1;
                DECLARE str VARCHAR(26) DEFAULT 'abcdefghijklmnopqrstuvwxyz';
                DECLARE startIndex INT;      #代表初始索引
                DECLARE len INT;             #代表截取的字符长度
                WHILE i<=insertcount DO
                    SET startIndex=FLOOR(RAND()*26+1);    #代表初始索引,随机范围1-26
                    SET len=FLOOR(RAND()*(20-startIndex+1)+1);    #代表截取长度,随机范围1-(26-startIndex+1)        【 content 要求长度为20,所以26取不到,因此最终结果:1 -(20-startIndex+1)】
                    INSERT INTO stringcontent(content) VALUES(SUBSTR(str,startIndex,len));
                    SET i=i+1;
                END WHILE;
          END $

          CALL test_randstr_insert(10)$
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容

  • 数据库简介关系型数据库MySQL安装和使用SQL语言 一、数据库简介 (一)数据库的发展 文件系统:磁盘文件存储数...
    哈喽别样阅读 435评论 0 1
  • 原文链接:http://blog.csdn.net/qq_22329521/article/details/538...
    越长越圆阅读 827评论 3 16
  • MySql基础(一) 数据库 & 数据库管理系统 区别 数据库:就是存储数据的仓库,是一个文件系统 数据库管理系统...
    AndroidCat阅读 233评论 0 1
  • 首先在Mysql中语言分为三种:1、数据定义语言(DDL):用来建立数据库、数据库对象和定义列的命令。包括:cre...
    张不二01阅读 131评论 0 0
  • 一、分类 1、DDL(Data Definition Language):数据库定义语言,用来定义数据库对象:表...
    小心陨石阅读 234评论 0 1