DDL:数据定义语言
 作用 : 用于完成对数据库对象(数据库、数据表、视图、索引等)的创建、删除、修改 
 
数据库操作
查询数据库
 - >  显示当前 mysql 中的数据库列表  
          > show databases;  
  - >  显示指定名称的数据的创建的 SQL 指令  
          > show create database 库名 ; 
 创建数据库
 - >  创建数据库  
          > create database 库名 ;  
  - >  创建数据库,当指定名称的数据库不存在时执行创建  
          > create database if not exists 库名 ;  
  - >  在创建数据库的同时指定数据库的字符集(字符集:数据存储在数据库中采用的编码格式 utf8 、 gbk )  
          > CREATE DATABASE IF NOT EXISTS 库名  CHARSET 'utf8'; 
 修改数据库字符集
 - >  修改数据库的字符集  
          > alter database 库名  CHARSET  字符集 ; 
 删除数据库
 - >  删除数据库  
          > drop database 库名 ;  
  - >  如果数据库存在则删除数据库  
          > drop database if exists 库名 ;  
 使用/切换数据库
 use  库名 ; 
 数据表操作
         创建完数据库之后,接下来就是在数据库中创建数据表。在MySQL 中,数据表以二维表格的形式展示,表格中的一行代表一条完整的数据记录,表格中的一列代表数据的某个特定属性。  
  需要注意:  
          在数据库中创建表之前,需要查看当前使用的数据库  
  语法: 
          select database();  
          然后切换到你需要操作的数据库  
          use db_name; 
 建表
         create table 表名 ( 字段 1  字段类型 , 字段 2  字段类型 , ... 字段 n  字段类型 ); 
  字段类型 : 
          int:整型  
          double:浮点型,例如 double(5,2) 表示最多 5 位,其中必须有 2 位小数,即最大值为 999.99;  
          char:固定长度字符串类型;  
          char(10): 'aaa ' 占 10 位  
          varchar:可变长度字符串类型;  
          varchar(10): 'aaa' 占 3 为  
          text:字符串类型;  
          blob:字节类型;  
          date:日期类型,格式为: yyyy-MM-dd ;  
          time:时间类型,格式为: hh:mm:ss  
          timestamp:时间戳类型  yyyy-MM-dd hh:mm:ss  会自动赋值  
          datetime:日期时间类型  yyyy-MM-dd hh:mm:ss  
          boolean:mysql不支持 ,oracle 支持  
  示例 : 
  创建一张存储学员信息的表 :stu  
  表中的字段有 :  
          s_id 一条数据的唯一标识符  int primary key auto_increment  
          s_name 学员姓名  varchar(30)  
          s_sex 学员性别  varchar(10)  
          s_age 学员年龄  int  
          s_class 学员所在班级  varchar(50)  
          s_num 学号  varchar(16)  
          s_type 学员专业  varchar(50)  
  sql 语句  
  create table stu(  
          s_id int primary key auto_increment,  
          s_name varchar(30),  
          s_sex varchar(10),  
          s_age int,  
          s_class varchar(50),  
          s_num varchar(16),  
          s_type varchar(50)  
  ); 
 查看所有表
         SHOW TABLES; 
 重命名表
         rename table 原表名  to  新表名 ; 
 查看创建表语句信息
         SHOW CREATE TABLE 表名 ;  
 修改字符集
         ALTER TABLE 表名  CHARACTER SET  修改后的字符集 ;  
          注意: 一般使用 utf8( 就是 utf-8) 
 查表字段信息
         DESC 表名 ;  
 备份表
         create table 新表名  as select * from  要备份的表的名称 ;  
  如 :  
          create table tname2 as select * from tname1;  
 备份表结构
         create table 新表名  like  要备份的表的名称 ;  
  如 :  
          create table tname2 like tname1;  
 删除表
         DROP TABLE 表名 ; 
 添加列
         ALTER TABLE 表名  ADD  添加的列名 填加的列字段类型 ;  
 修改列
alter table 表名 modify 要修改的列名 修改后的字段类型;
删除列
         alter table 表名  drop  列名 ;  
          注意: 一次只能删一列 
 列重命名
ALTER TABLE 表名 CHANGE 原列名 新列名 新字段类型;
DML:数据操作语言
插入数据
 作用 : 给表中添加数据 
          insert into  表名 ( 列名 1,  列名 2....)  values  ( 值 1, 值 2....);  
 示例: 
          insert into  stus(stu_num,stu_name,stu_gender,stu_age,stu_tel)  
          values ( '20210101' , ' 张三 ' , ' 男 ' , 21 , '13030303300' );  
          # 数据表名后的字段名列表顺序可以不与表中一致,但是 values 中值的顺序必须与表名 后字段名顺序对应  
          insert into  stus(stu_num,stu_name,stu_age,stu_tel,stu_gender)  
          values ( '20210103' , ' 王五 ' , 20 , '13030303302' , ' 女 ' );  
          # 当要向表中的所有列添加数据时,数据表名后面的字段列表可以省略,  
          #但是 values 中的值的顺序要与数据表定义的字段保持一致 ;  
          insert into  stus  values ( '20210105' , ' 孙 琦' , ' 男 ' , 21 , '13030303304' , '666666' ); 
           # 不过在项目开发中,即使要向所有列添加数据 , 也建议将列名的列表显式写出来 ( 增强 SQL的稳定性 )  
          insert into  stus(stu_num,stu_name,stu_gender,stu_age,stu_tel,stu_qq)  
          values ( '20210105' , ' 孙琦 ' , ' 男 ' , 21 , '13030303304' , '666666' ); 
 修改数据
         update  表名  set  列名 1= 值 1 ,列名 2= 值 2 [ where  条件 ];  
 示例: 
          # 将学号为 20210105 的学生姓名修改为 “ 孙七 ” (只修改一列)  
          update  stus  set  stu_name= ' 孙七 '  where  stu_num= '20210105' ;  
          # 将学号为 20210103 的学生 性别修改为 “ 男 ”, 同时将 QQ 修改为  777777 (修改多列)  
          update  stus  set  stu_gender= ' 男 ' ,stu_qq= '777777'  where   stu_num= '20210103' ;  
          # 根据主键修改其他所有列  
          update  stus  set  stu_name= ' 韩梅梅' ,stu_gender= ' 女 ' ,stu_age= 18 ,stu_tel= '13131313311'  ,stu_qq= '999999'  where  stu_num= '20210102' ;  
          # 如果 update 语句没有 where 子句,则表示修改当前表中所有行(记录)  
          update  stus  set  stu_name= 'Tom' ; 
 删除数据
         delete from 表名  [where  条件 ];  
 示例: 
          # 删除学号为 20210102 的学生信息  
          delete from  stus  where  stu_num= '20210102' ;  
          # 删除年龄大于 20 岁的学生信息 ( 如果满足 where 子句的记录有多条,则删除多条记录 )  
          delete from  stus  where  stu_age> 20 ;  
          # 如果删除语句没有 where 子句,则表示删除当前数据表中的所有记录 ( 敏感操作 )  
          delete from  stus; 
 DQL:数据查询语言
查询全表
         select * from 表名 ;  
 查询指定列
select 列名1,列名2,… from 表名;
条件查询
         select * from 表名  where  条件;      
 注意: 
  条件查询就是在查询时给出 WHERE 子句,在 WHERE 子句中可以使用如下运算符及关键 字:  
          =、 != 、 > 、 < 、 <= 、 > 、 >=  
          BETWEEN…AND (等价 <= 和 >=)  
          IN(set) (包含 )  
          IS NULL (非空 )  
          AND (逻辑与 )  
          OR (逻辑或 )  
          NOT (逻辑非 )  
          XOR (逻辑异或 ) 
 示例: 
  --  查询成绩小于 80 的学员  
  select  *  from  stu  where  score <  80 ;  
  --  查询成绩等于 100 的学员  
  select  *  from  stu  where  score =  100 ;  
  --  查询成绩在 85~100 的学员  
  select  *  from  stu  where  math  between  80  and  100 ;  
  --  查询姓名叫做 “ 张三 ” 或者 “ 李四 ” 的所有学生信息。  
  select  *  from  stu  where  name beteween  " 张三 "  and  " 李四 " ;  
  --  查询成绩不小于 80 的学员  
  select  *  from  stu  where not  score <  80 ;  
  --  查询姓名不叫做 “ 张三 ” 或者 “ 李四 ” 的所有学生信息。  
  select  *  from  stu  where  name  not  beteween  " 张三 "  and  " 李四 " ;  
  --  查询姓名叫做 “ 张三 ” 或者 “ 李四 ” 的所有学生信息。  
  select  *  from  stu  where  name  in  ( " 张三 " , " 李四 " );  
  --  查询成绩小于 0 或大于 100 的学员 
  select  *  from  stu  where  score <  0  or  score >  100 ;  
  --  查询性别为空的学员  
  select  *  from  stu  where  sex  IS  NULL ;  
 模糊查询
 当想查询姓名中包含 a 字母的学生时就需要使用模糊查询了。模糊查询需要使用关键字 LIKE。  
          _:任意一个字母  
          %:任意 0~n 个字母  ' 张 %'  
 示例:
 --  查找姓名为 3 个字母的学生信息  
  select  *  from  stu  where  name  like  '___' ;// 注意是 3 个 _ ,表示匹配 3 个字符  
  --  查找以字母 b 开头的学生信息  
  select  *  from  stu  where  name  like  'b%' ;  
          MySQL 同样也支持其他正则表达式的匹配,  MySQL 中使用  REGEXP  操作符来进行正则 表达式匹配。 
  
  示例: 
   --  查找姓名以 l 开头且以 y 结尾的学生信息  
  select  *  from  stu  where  name regexp  '^l'  and  name regexp  'y$' ;  
 去重
 关键字 :distinct  
  示例 
  --  查询 stu 表中 age 字段,剔除重复行  
  select distinct  age  from  stu; 
 计算列
 对从数据表中查询的记录的列进行一定的运算之后显示出来  
          +,-,*,/,%          
 例                                                             
  --  出生年份  =  当前年份  -  年龄  
  select  stu_name, 2021 -stu_age  from  stus; 
 别名
         如果在连接查询的多张表中存在相同名字的字段,我们可以使用 表名 . 字段名  来进行区 分,如果表名或字段名太长则不便于SQL 语句的编写,我们可以使用数据表别名  
  示例 
  --  字段起别名  
  select  name  AS  姓名  from  stu;  
  --  表名起别名  
  select  s .name ,s .sex  from  stu  AS  s;  
  -- AS 可以省略  
  select  name  姓名  from  stu;  
  select  s .name ,s .sex  from  stu s;  
 排序order by
 将查询到的满足条件的记录按照指定的列的值升序 / 降序排列  
  语法:  
          select * from 表名  where  条件  order by  列名  asc|desc;  
                  order by 列名 表示将查询结果按照指定的列排序  
                          asc 按照指定的列升序(默认)  
                          desc 按照指定的列降序 
  #  单字段排序  
  select  *  from  stu  where  age> 15  order by  score  desc ;  
  #  多字段排序 : 先满足第一个排序规则 , 当第一个排序的列的值相同时再按照第二个列的  
  规则排序  
  select  *  from  stus  where  age> 15  order by  score  asc ,age  desc ; 
 聚合函数
 聚合函数是用来做纵向运算的函数:  
  COUNT() :统计指定列不为 NULL 的记录行数;  
  MAX() :计算指定列的最大值,如果指定列是字符串类型,那么使用字符串排序运算;  
  MIN() :计算指定列的最小值,如果指定列是字符串类型,那么使用字符串排序运算;  
  SUM() :计算指定列的数值和,如果指定列类型不是数值类型,那么计算结果为 0 ;  
  AVG() :计算指定列的平均值,如果指定列类型不是数值类型,那么计算结果为 0 ;  
 例: 
  --  统计年龄大于 20 的学员人数  
  select count (*)  as  cnt  from  stu  where  age> 20 ;  
  --  统计学员的总年龄  
  select  sum(age)  from  stu;  
  --  统计学员的平均年龄以及总年龄  
  select  sum(age),avg(age)  from  stu;  
  --  统计学员的最低年龄以及最高年龄  
  select  max(age),min(age)  from  stu;  
  --  计算班级平均分  
  select  avg(score)  from  stu; 
 分组查询
 分组:就是将数据表中的记录按指定的列进行分组  
  语法  
  select  分组字段 / 聚合函数  
  from  表名  
  [ where  条件 ]  
  group by  分组列名  [ having  条件 ]  
  [ order by  排序字段 ]  
 注意: 
  语句执行顺序:  
  1, 先根据 where 条件从数据库查询记录  
  2,group by 对查询记录进行分组  
  3, 执行 having 对分组后的数据进行筛选  
  4, 排序 
 例: 
          -- 先对查询的学生信息按性别进行分组(分成了男、女两组),然后再分别统计每组 学生的个数  
          select  stu_gender, count (stu_num)  from  stus  group by  stu_gender;  
          -- 先对查询的学生信息按性别进行分组(分成了男、女两组),然后再计算每组的平 均年龄  
          select  stu_gender,avg(stu_age)  from  stus  group by  stu_gender;  
          -- 先对学生按年龄进行分组,然后统计各组的学生数量,还可以对最终的结果排序  
          select  stu_age, count (stu_num)  from  stus  group by  stu_age  order by  stu_age;  
          -- 查询所有学生,按年龄进行分组,然后分别统计每组的人数,再筛选当前组人数 >1 的组,再按年龄升序显示出来  
          select  stu_age, count (stu_num)  
          from  stus  
          group by  stu_age  
          having count (stu_num)> 1  
          order by  stu_age;  
          -- 查询性别为 ' 男 ' 的学生 , 按年龄进行分组 , 然后分别统计每组的人数 , 再筛选当前组人 数>1 的组 , 再按年龄升序显示出来  
          mysql>  select  stu_age, count (stu_num)  
          ->  from  stus  
          ->  where  stu_gender= ' 男 '  
          ->  group by  stu_age  
          ->  having count (stu_num)> 1  
          ->  order by  stu_age;  
 分页查询
语法:
 select  查询的字段  
  from  表名  
  where  条件  
  limit  param1,param2;  
  注意 :  
          - param1:表示获取查询语句的结果中的第一条数据的索引(索引从 0 开始)  
          - param2:表示获取的查询记录的条数(如果剩下的数据条数 <param2 ,则返回剩下的 所有记录)  
 注意: 
  --  示例  
  --  假如 : 对数据表中的学生信息进行分页显示,总共有 10 条数据,我们每页显示 3 条  
  --  总记录数: `count 10`  
  --  每页显示: `pageSize 3 
  --  总页数: `pageCount=count%pageSize==0?  
  count/pageSize:count/pageSize+1`  
  --  查询第一页:  
  select  *  from  stus [ where  ...]  limit  0 , 3 ; ( 1 - 1 )* 3  
  --  查询第二页:  
  select  *  from  stus [ where  ...]  limit  3 , 3 ; ( 2 - 1 )* 3  
  --  查询第三页:  
  select  *  from  stus [ where  ...]  limit  6 , 3 ; ( 3 - 1 )* 3  
  --  查询第四页:  
  select  *  from  stus [ where  ...]  limit  9 , 3 ; ( 4 - 1 )* 3  
  --  如果在一张数据表中:  
  -- pageNum 表示查询的页码  
  -- pageSize 表示每页显示的条数  
  --  通用分页语句如下:  
  select  *  from  stus [ where  ...]  limit  (pageNum- 1 )*pageSize,pageSize;  
 约束
 -  保证数据的有效性  
  -  保证数据的完整性  
  -  保证数据的正确性 
   -  非空约束( not null ):限制此列的值必须提供,不能为 null  
  -  唯一约束( unique ):在表中的多条数据,此列的值不能重复  
  -  主键约束( primary key ):非空 + 唯一,能够唯一标识数据表中的一条数据  
  -  自增长约束 (auto_increment): 每次 +1, 从 1 起  
  -  检查约束( check ):保证列中的值满足某一条件  
  -  默认约束( default ):保存数据时 , 未指定值则采用默认值  
  -  外键约束( foreign key ):建立不同表之间的关联关系 
 多表查询
 语法: select  列名 1, 列名 2,.. from  表 1, 表 2,.. where  判断语句 ;  
  示例 
  --  查看 stu 和 grade 表中的学生学号、姓名、班级、成绩信息  
  select  s.*,g.*  from  stu s,grade g  where  s .id  = g .stu_id ;  
  注意: 没有条件会出现笛卡尔积 
 视图:虚拟表
 视图,就是由数据库中一张表或者多张表根据特定的条件查询出得数据构造成得虚拟表  
 优点: 
  安全性:  
          如果我们直接将数据表授权给用户操作,那么用户可以CRUD 数据表中所有数据,加 入我们想要对数据表中的部分数据进行保护,可以将公开的数据生成视图,授权用户访 问视图;用户通过查询视图可以获取数据表中公开的数据,从而达到将数据表中的部分 数据对用户隐藏。  
  简单性:  
          如果我们需要查询的数据来源于多张数据表,可以使用多表连接查询来实现;我们 通过视图将这些连表查询的结果对用户开放,用户则可以直接通过查询视图获取多表数 据,操作更便捷。  
  数据独立:  
          一旦视图的结构确定了,可以屏蔽表结构变化对用户的影响,源表增加列对视图没 有影响;源表修改列名,则可以通过修改视图来解决,不会造成对访问者的影响。  
 创建视图
 CREATE VIEW  视图名称  AS <SELECT 语句 >  
  create view  view_test1  
  AS  
  select  *  from  students 
 查询视图结构
 desc  视图名称 ; 
 修改视图
 create OR REPLACE view  视图名称  
  AS  查询语句  
  # 或  
  alter view  视图名称  
  AS  查询语句 
 例: 
  #  方式 1  
  create OR REPLACE view  view_test1  
  AS  
  select  *  from  students  where  stu_gender= ' 女 ' ;  
  #  方式 2  
  alter view  view_test1  
  AS  
  select  *  from  students  where  stu_gender= ' 男 ' ; 
 特性
 视图是虚拟表,查询视图的数据是来源于数据表的。当对视图进行操作时,对原数据表中  
  的数据是否由影响呢?  
  查询操作 :如果在数据表中添加了新的数据,而且这个数据满足创建视图时查询语句的条  
  件,通过查询视图也可以查询出新增的数据;当删除原表中满足查询条件的数据时,也会  
  从视图中删除。  
  新增数据: 如果在视图中添加数据,数据会被添加到原数据表  
  删除数据: 如果从视图删除数据,数据也将从原表中删除  
  修改操作: 如果通过修改数据,则也将修改原数据表中的数据  
  视图的使用建议 :  对复杂查询简化操作,并且不会对数据进行修改的情况下可以使用视图。  
 触发器
         触发器是数据库的回调函数,它会在指定的数据库事件发生时自动执行调用  
          1、只有每当执行 delete , insert 或 update 操作时,才会触发,并执行指定的一 条或多条SQL 语句。  
  例如 :  
          可以设置触发器,当删除persons 表中 lucy 的信息时,自动删除 grade 表中与 lucy相关的信息  
          2、触发器常用于保证数据一致,以及每当更新或删除表时,将记录写入日志表 
 创建触发器
 --  语法 :  
  --  修改 sql 语句结束符为  ||  
  delimiter ||  
  --  创建触发器  
  create  trigger  触发器名  [after|before] [ delete |update|delete]  on  表名  
  for each row  
  begin  
  语句 ;  
  end ||  
  delimiter ;  
  old: 老数据  
  new: 新数据 
 查看触发器
 语法: show triggers;  
 删除触发器
 drop trigger  触发器名 ; 
 练习
 --  准备工作 , 建库 , 切库  
  CREATE DATABASE IF NOT EXISTS  lx  CHARSET  'UTF8' ;  
  USE  lx;  
  -- 1 、创建 persons 表 ,id 设置为主键 , 表的格式 (id integer primary key,name text,addr text,class text)  
  CREATE TABLE  person(  
  id  integer  primary key auto_increment ,  
  name  text ,  
  addr  text ,  
  class  text  
  );  
  -- 2 、创建 grade 表 , 设置约束条件 (score>0) ,表的格式 (id integer, score integer, year text)  
  create table  grade(  
  id  integer , score  integer ,  year text  
  ); 
  -- 3 、追加相应的数据 , 见下页  
  insert into  person (name, addr, class)  value  
  ( 'lucy' , 'beijing' , 'class_A' );  
  insert into  person (name, addr, class)  value  
  ( 'peter' , 'tianjing' , 'class_B' );  
  insert into  person (name, addr, class)  value  
  ( 'bob' , 'hebei' , 'class_A' );  
  insert into  grade (id, score,  year )  value  ( 1 , 78 , '2013' );  
  insert into  grade (id, score,  year )  value  ( 2 , 98 , '2013' );  
  insert into  grade (id, score,  year )  value  ( 3 , 80 , '2013' );  
  insert into  grade (id, score,  year )  value  ( 1 , 88 , '2014' );  
  -- 4 、打印所有学生的信息 : 包括 name,addr,class,score,year  
  select  p.*,g .score ,g .year  from  person p,grade g  where  p .id  = g .id ;  
  -- 5 、将打印所以学生信息的语句 , 创建视图 PersonsGrade, 方便后面使用  
  create view  persongrade  as select  p.*,g .score ,g .year  from  person  
  p,grade g  where  p .id  = g .id ;  
  -- 6 、查看最高分数是多少?  
  select max (score)  from  persongrade;  
  -- 7 、查看每个班的平均分,以及对应的班级名称和班级人数  
  select  class  班级 ,  count ( distinct  id)  人数 ,  avg (score)  from  
  persongrade  group by  class;  
  -- 8 、在 persons 表中 id 列创建一个索引 persons_id_index  
  create index  person_id_index  on  person (id);  
  -- 9 、查看 lucy 在 2013 年的成绩  
  select  *  from  persongrade  where  name= 'lucy'  and  year = '2013' ;  
  -- 10 、 bob 要退学,必须要删除 bob 所有的信息 ( 包括成绩单 ), 通过设置触发器,自动删除bob 相关的所有数据,设置触发器 tg_delete  
  delimiter  ||  
  create trigger  tg_delete  after delete on  person  for each row  
  begin  
  delete from  grade  where  grade .id  = old .id ;  
  end  ||  
  delimiter  ;  
  -- 11 、执行删除 bob 的操作  
  delete from  person  where  name= 'bob' ;  
  -- 12 、查看所有人的信息,确定是否执行了删除操作  
  select  *  from  person;  
  select  *  from  grade;  
  select  *  from  persongrade;