MySQL 笔记

一、数据库

1.MySQL 的三层结构


  • 所谓安装 MySQL 数据库,就是在主机上安装了一个数据库管理系统(DBMS),这个管理程序可以管理多个数据库。

  • 一个数据库中可以创建多个表,以保存数据(信息)。

  • 数据库管理系统、数据库和表的关系

1)数据在数据空中的存储方式

  • 表一行称为一条记录 ——> 在 Java 程序中一条记录往往用对象来表示
    在这里插入图片描述

2)SQL 语句分类

在这里插入图片描述

2.Java 操作 MySQL


  • 1.创建一个商品,选用适当的数据类型
  • 2.添加两条数据
  • 3.删除表
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;

@SuppressWarnings({"all"})
public class JavaMysql {

    public static void main(String[] args) throws SQLException, ClassNotFoundException {

        //这里老韩给大家演示一下 java 程序如何操作Mysql

        //加载类,得到mysql连接
        Class.forName("com.mysql.jdbc.Driver");
        Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/hsp_db02", "root", "hsp");

        //创建一个商品hsp_goods表, 选用适当的数据类型
        //添加2条数据
        //删除表goods

        //这里可以编写sql 【create , select , insert , update ,delete ...】
        //String sql = "create table hsp_goods ( id int, name varchar(32), price double, introduce text)" ;
        //String sql = "insert into hsp_goods values(1, '华为手机', 2000, '这是不错的一款手机')" ;
        String sql = "drop table hsp_goods" ;

        //得到statement对象,把sql 语法发送给mysql执行
        Statement statement = connection.createStatement();
        statement.executeUpdate(sql);

        //关闭连接
        statement.close();
        connection.close();
        System.out.println("成功~");

    }
}

3.创建数据库


#演示数据库的操作
#创建一个名为 hsp_db01 的数据库
CREATE DATABASE hsp_db01;

#删除数据库指令
DROP DATABASE hsp_db01;

#创建一个使用 utf-8 字符集的数据库
CREATE DATABASE hspdb_02 CHARACTER SET utf8

#创建一个使用 utf8 的字符集,并带校对规则的数据库
CREATE DATABASE hspdb_03 CHARACTER 
SET utf8 COLLATE utf8_bin

#下面是一条查询 SQL语句
SELECT * FROM t1 WHERE NAME = 'tom';

4.查看数据库


#显示数据库语句
SHOW  DATABASES

#查看前面创建的数据库的定义信息
SHOW CREATE DATABASE hsp_db01

#在创建数据库、表的适合,为了规避关键字,可以使用反引号解决
#和波浪线在一起的那个点
CREATE DATABASE `CREATE`

5.备份、恢复数据库


  • 备份数据库(注意:在 DOS 中执行)

    mysqldump -uroot -p -B 数据库1 数据库2 数据库n > 文件名.sql

  • 恢复数据库(注意:进入SQLyog再执行)

    ​ Source 文件名.sql

#备份,要在 DOS 下执行 mysqldump 指令
mysqldump -u root -p -B hsp_db02 hsp_db03 > d:\\bak.sql
#回复数据库(注意:进入MySQL命令行再执行)
source d:\\bak.sql
  • 备份数据库的表

    mysqldump -u root -p 数据库 表1 表2 表n > d://文件名

二、表

1.创建表


CREATE TABLE table_name (
    field1 datatype,
    field2 datatype,
    field3 datatype
)character set 字符集 collate 校对规则 engine 引擎
  • field:指定列名, datatype 指定列的类型(字段类型)
  • character set :如果不指定为所在数据库字符集
  • collate:若不指定则为梭子啊数据库的校对规则
  • engine:引擎

2.MySQL 数据类型(列类型)


1)数值型(INT)的基本使用

  • 说明:在足够满足需求的情况下,尽量选择占用空间小的类型

  • 应用实例

#演示整型的基本使用
#说明:表的字符集、校验规则、存储引擎这里先设为默认 -128 - 127
#如果没有指定 unsigned 则这个 TINYINT 就是有符号的
CREATE TABLE `t3`(
	id TINYINT
);
CREATE TABLE `t4`(
	id TINYINT UNSIGHED #无符号的 0-255
);
INSERT INTO t3 VALUES(-128);#这是非常简单的添加语句

2)数值型(BIT)的使用

#演示 bit 类型的使用
#1. BIT(m) m 在 1 - 64
#2.添加数据的范围给定的位数,如 255 就是 11111111 共八位
#3.显示按照 bit
#4.查询的时候仍然可以用数来查询
CREATE TABLE `t5` (num BIT(8));

3)数值型(小数)的使用

  • FLOAT / DOUBLE【UNSIGNED】
    FLOAT 单精度 DOUBLE 双精度
  • DECIMAL[M, D] 【UNSIGNED】
    • 可以支持更加精确的小数位,M 是小数位数(精度)的总数,D 是小数点后面的位数
    • 如果 D 是 0 则该值没有小数点或者分数部分,M 最大是 65。D 最大是 30。如果 D 被省略的话则默认是 0,如果 M 被省略则默认是 10
    • 建议:如果希望小数的精度高,推荐使用 decimal
#演示 decimal 类型、float 类型、double 类型的使用

#创建表
CREATE TABLE `t6`(
	num1 FLOAT,
    num2 DOUBLE,
    num3 DECIMAL30,20);
#添加数据
INSERT INTO t6 VALUES(88.123566678, 88.5531654541651, 88.6455321678);

4)字符串的基本使用

  • CHAR(size)
    • 固定长度的字符串 最大 255 字符
  • VARCHAR(size) 0 - 21844
    • 可变长度字符串 最大 65535 字节【 utf8 编码最大 21844 字符 其中 1- 3 个字节用于记录大小】,65535 - 3 字节按照三个字节分组 65532 / 3 = 21844
#演示字符串的使用 char varchar
#注释的快捷键 shift + ctrl + c,取消注释 shift + ctrl + r
CREATE TABLE t9(
	`name` CHAR(255));
)
CREATE TABLE t10(
	`name` VARCHAR(21844)
);
  • 字符串的使用细节

    • 细节1:
      char(4) 这个 4 表示的是字符数(最大是255),不是字节数,不管是中文还是字母都要放四个,按照字符计算

      varchar(4) 这个 4 表示的是字符数,不管是字母还是中文都以定义好的表的编码来存储数据,如 utf8 下的 4 个字符就是 12 个字节

      ​ 不管是中文还是英文字母都是最多存放 4 个,是根据使用的字符集来计算的。

    • 细节2:
      char(4) 是定长(固定的大小)也就是说,即使你插入的是 ‘aa’ ,也会占用分配的 4 个字符的空间

      varchar(4) 是变长(变化的大小),就是说,如果插入的是‘aa’实际占用的空间不是 4 个字符,而是按照实际占用的空间来分配的,varchar 本身还需要 1-3 个字节来记录存放内容长度。

    • 细节3:
      什么时候使用 char ,什么时候使用 varchar?
      1.如果数据是定长,推荐使用 char,比如 md5 的密码,邮箱,手机号,身份号码

      2.如果一个字段的长度是不确定的,我们使用 varchar,比如留言、文章
      查询速度 char > varchar

    • 细节4
      在存放文本时,可以用 Text 数据类型,可以将 TEXT 列是为 VARCHAR 列,注意 TEXT 不能有默认值,大小为 0 - 2^16 字节
      如果希望存入更多的字符,可以选择 MEDIUMTEXT 0 - 2^24 或者
      LONGTEXT 0 - 2^32

    #演示字符串类型的使用细节
    #char(4) 和 varchar(4) 这个4表示的是字符,而不是字节, 不区分字符是汉字还是字母
    CREATE TABLE t11(
    	`name` CHAR(4));
    INSERT INTO t11 VALUES('韩顺平好');
    
    SELECT * FROM t11;
    
    CREATE TABLE t12(
    	`name` VARCHAR(4));
    INSERT INTO t12 VALUES('韩顺平好');
    INSERT INTO t12 VALUES('ab北京');
    SELECT * FROM t12;
    
    #如果varchar 不够用,可以考虑使用mediumtext 或者longtext, 
    #如果想简单点,可以使用直接使用text
    CREATE TABLE t13( content TEXT, content2 MEDIUMTEXT , content3 LONGTEXT);
    INSERT INTO t13 VALUES('韩顺平教育', '韩顺平教育100', '韩顺平教育1000~~');
    SELECT * FROM t13;
    

5)日期类型的基本使用

#演示日期类型的基本使用
CREATE TABLE `birthday6`(
	t1 DATE,
	t2 DATETIME,
	t3 TIMESTAMP NOT NULL DEFAULT
	CURRENT_TIMESTAMP ON UPDATE
	CURRENT_TIMESTAMP);
	
	INSERT INTO birthday6(t1, t2)
	VALUES('2022-11-11', '2022-11-11 10:10:10')
	SELECT * FROM birthday6;
)
  • 细节说明:TimeStamp 在 Insert 和 update 的时候会自动的更新。

6)创建表的练习

在这里插入图片描述

#创建表的练习
CREATE TABLE `emp`(
	`Id` INT,
	`name` VARCHAR(255),
	`sex`	CHAR(1),
	`birthday`	DATE,
	`entry_date`	DATETIME,
	`job`	VARCHAR(255),
	`Salary` DOUBLE,
	`resume`	TEXT);

3.修改和删除表


1)修改表 —— 基本介绍

  • 使用 ALTER TABLE 语句来追加、需要改或者删除列

    1. 添加列

      ALTER TABLE tablename ADD colum datatype, column datatype;   
      
    2. 修改列

      ALTER TABLE tablename MODIFY column datatype,column datatype;
      
    3. 删除列

      ALTER TABLE tablename DROP column;
      #查看表的结构: desc 表名;
      

2)应用实例

在这里插入图片描述

#添加一个 image 列,类型为 varchar,在 resume 后面
ADD image VARCHAR(255) NOT NULL DEFAULT''
AFTER RESUME
CHANGE `name` `username` VARCHAR(64) NOT NULL DEFAULT '';
#修改 job 列,使其长度为 60
ALTER TABLE `emp` MODIFY `job` VARCHAR ( 60 );
#删除 sex 列
ALTER TABLE `emp` DROP sex;
#将表名改为 employee
RENAME TABLE emp TO employee;
#将列表字符集修改为 utf8
ALTER TABLE `employee` CHARACTER SET utf8;
#列名 name 修改为 user_name
ALTER TABLE employee 
	CHANGE `name` `username` VARCHAR(64) NOT NULL DEFAULT '';

三、数据库 CRUD 语句

CRUD:creat、read、update、delete,增删改查

1.Insert 语句


1)使用 INSERT 语句向表中插入数据

INSERT INTO table_name(column, column, column)
VALUES (value, value, value)
  • 案例演示

    #练习insert 语句
    -- 创建一张商品表goods (id  int , goods_name varchar(10), price double );
    -- 添加2条记录
    CREATE TABLE `goods` (
    	id INT ,
    	goods_name VARCHAR(10), -- 长度10
    	price DOUBLE NOT NULL DEFAULT 100 );
    -- 添加数据
    INSERT INTO `goods` (id, goods_name, price) 
    	VALUES(10, '华为手机', 2000);
    INSERT INTO `goods` (id, goods_name, price) 
    	VALUES(20, '苹果手机', 3000);
    SELECT * FROM goods;
    

2)insert 细节说明

  • 插入的数据应该与字段的数据类型相同或者可以转换,如 ‘10’ 是可以转换成 int 的

  • 数据的长度应在列的规定范围内,例如:不能将一个长度为 80 的字符串加入到长度为 40 的列中

  • 在 values 中列出的数据位置必须与加入到列的排列位置顺序相对应

  • 字符和日期型数据应包含在单引号中

  • 列可以插入空值【前提是该字段允许为空】,insert into table value(null)

  • INSERT INTO table_name VALUES 后面可以跟多个括号来添加多个记录

  • 如果是给表中的所有字段添加数据,可以不写前面的字段名称

  • 默认值的使用:如果不给某个字段值的时候,如果有默认值会添加,否则报错

  • 案例演示

    #说明insert 语句的细节
    -- 1.插入的数据应与字段的数据类型相同。
    --       比如 把 'abc' 添加到 int 类型会错误
    INSERT INTO `goods` (id, goods_name, price) 
    	VALUES('韩顺平', '小米手机', 2000);
    -- 2. 数据的长度应在列的规定范围内,例如:不能将一个长度为80的字符串加入到长度为40的列中。
    INSERT INTO `goods` (id, goods_name, price) 
    	VALUES(40, 'vovo手机vovo手机vovo手机vovo手机vovo手机', 3000);
    -- 3. 在values中列出的数据位置必须与被加入的列的排列位置相对应。
    INSERT INTO `goods` (id, goods_name, price)  -- 不对
    	VALUES('vovo手机',40, 2000);
    -- 4. 字符和日期型数据应包含在单引号中。
    INSERT INTO `goods` (id, goods_name, price) 
    	VALUES(40, vovo手机, 3000); -- 错误的 vovo手机 应该 'vovo手机'
    -- 5. 列可以插入空值[前提是该字段允许为空],insert into table value(null)
    INSERT INTO `goods` (id, goods_name, price) 
    	VALUES(40, 'vovo手机', NULL);
    -- 6. insert into tab_name (列名..)  values (),(),()  形式添加多条记录
    INSERT INTO `goods` (id, goods_name, price) 
    	VALUES(50, '三星手机', 2300),(60, '海尔手机', 1800);
    -- 7. 如果是给表中的所有字段添加数据,可以不写前面的字段名称
    INSERT INTO `goods`   
    	VALUES(70, 'IBM手机', 5000);
    -- 8. 默认值的使用,当不给某个字段值时,如果有默认值就会添加默认值,否则报错
          -- 如果某个列 没有指定 not null ,那么当添加数据时,没有给定值,则会默认给null
          -- 如果我们希望指定某个列的默认值,可以在创建表时指定
    INSERT INTO `goods` (id, goods_name)   
    	VALUES(80, '格力手机');
    
    SELECT * FROM goods;
    
    INSERT INTO `goods2` (id, goods_name)   
    	VALUES(10, '顺平手机');
    SELECT * FROM goods2;
    

2.update 语句


1)使用 update 语句修改表中数据

#修改列中所有的元素为一个量
UPDATE tab_name
	SET col_name = variable;
#修改列中的一行为某个量
UPDATE tab_name
	SET col_name = variable
	WHERE user_name = 'name';
  • 案例演示

    -- 演示update语句
    -- 要求: 在上面创建的employee表中修改表中的纪录
    -- 1. 将所有员工薪水修改为5000元。[如果没有带where 条件,会修改所有的记录,因此要小心]
    UPDATE employee SET salary = 5000 
    -- 2. 将姓名为 小妖怪 的员工薪水修改为3000元。
    UPDATE employee 
    	SET salary = 3000 
    	WHERE user_name = '小妖怪' 
    -- 3. 将 老妖怪 的薪水在原有基础上增加1000元
    INSERT INTO employee 
    	VALUES(200, '老妖怪', '1990-11-11', '2000-11-11 10:10:10', '捶背的', 5000, '给大王捶背', 'd:\\a.jpg');
    UPDATE employee 
    	SET salary = salary + 1000 
    	WHERE user_name = '老妖怪' 
    -- 可以修改多个列的值
    UPDATE employee 
    	SET salary = salary + 1000 , job = '出主意的'
    	WHERE user_name = '老妖怪' 
    SELECT * FROM employee;
    

2)使用细节

  • update 语法可以用新值更新原有表行中的各列
  • set 字句指示要修改哪些列和要给予哪些值
  • where 字句指定应更新哪些行。如果没有 where 字句,则更新所有的行,使用时应注意
  • 如果需要修改多个字段,可以使用 SET 字段1 = 值1, 字段2 = 值2……;

3.delete 语句


1)使用 delete 语句删除表中的数据

DELETE FROM tab_name
#如果不加 where 就会删除表中所有的数据
	[WHERE where_definition]
  • 案例演示

    -- delete 语句演示
    
    --  删除表中名称为’老妖怪’的记录。
    DELETE FROM employee 
    	WHERE user_name = '老妖怪';
    --  删除表中所有记录, 老师提醒,一定要小心
    DELETE FROM employee;
    

2)使用细节

  • 如果不使用 where 字句,将删除表中的所有数据

  • delete 不能删除某一列的值,可以通过 update 将其设置为 null 或者 ‘ ’

  • 使用 delete 语句仅删除记录而不删除表的本身,如果要删除表,使用 drop table 语句

  • 案例演示

    -- Delete语句不能删除某一列的值(可使用update 设为 null 或者 '')
    UPDATE employee SET job = '' WHERE user_name = '老妖怪';
    
    SELECT * FROM employee
    
    -- 要删除这个表
    DROP TABLE employee;
    

4.select 语句


1)基本语法

#查出表中的所有数据
-- DISTINCE 可选,指显示结果的时候是否去掉重复的数据
SELECT [DISTINCT] * 
	FROM tab_name;
#查出表中指定列名的数据
SELECT [DISTINCT] column1, column2, column3...
	FROM tab_name;

2)案例演示

SELECT * FROM student;
-- 查询表中所有学生的信息。
SELECT * FROM student;
-- 查询表中所有学生的姓名和对应的英语成绩。
SELECT `name`,english FROM student;
-- 过滤表中重复数据 distinct 。
SELECT DISTINCT english FROM student;
-- 要查询的记录,每个字段都相同,才会去重
SELECT DISTINCT `name`, english FROM student;

3)课堂练习

  • 使用表达式对查询的列进行计算

    SELECT * expression
    	FROM tab_name;
    
  • 在 select 语句中可使用 as 语句

    SELECT col_name as other_name from col_name;
    
  • 案例演示

    -- select 语句的使用
    
    -- 统计每个学生的总分
    SELECT `name`, (chinese + english + math) 
    	FROM student;
    -- 在所有学生总分加10分的情况
    -- SELECT 后选择的是列或者对列做操作,最后显示出来作为列名
    SELECT `name`, (chinese + english + math + 10) 
    	FROM student;
    -- 使用别名表示学生分数。
    SELECT `name` AS '名字', (chinese + english + math + 10) AS total_score 
    	FROM student;
    
    • 效果

3)在 WHERE 字句中常用的运算符

在这里插入图片描述

  • 案例演示

    -- select 语句
    -- 查询姓名为赵云的学生成绩
    -- WHERE 是选择行,或者对行中按照元素进行限制,显示出来作为行名
    SELECT * FROM student 
    	WHERE `name` = '赵云'
    	
    -- 查询英语成绩大于90分的同学
    SELECT * FROM student 
    	WHERE english > 90
    	
    -- 查询总分大于200分的所有同学
    SELECT * FROM student 
    	WHERE (chinese + english + math) > 200
    	
    -- 查询math大于60 并且(and) id大于4的学生成绩
    SELECT * FROM student
    	WHERE math >60 AND id > 4
    	
    -- 查询英语成绩大于语文成绩的同学
    SELECT * FROM student
    	WHERE english > chinese
    	
    -- 查询总分大于200分 并且 数学成绩小于语文成绩,的姓赵的学生.
    -- 赵% 表示 名字以韩开头的就可以,模糊查询
    SELECT * FROM student
    	WHERE (chinese + english + math) > 200 AND 
    		math < chinese AND `name` LIKE '赵%'
    		
    -- 查询英语分数在 80-90之间的同学。
    SELECT * FROM student
    	WHERE english >= 80 AND english <= 90;
    SELECT * FROM student
    	WHERE english BETWEEN 80 AND 90; -- between .. and .. 是 闭区间
    	
    -- 查询数学分数为89,90,91的同学。
    SELECT * FROM student 
    	WHERE math = 89 OR math = 90 OR math = 91;
    SELECT * FROM student 
    	WHERE math IN (89, 90, 91);
    	
    -- 查询所有姓李的学生成绩。
    SELECT * FROM student 
    	WHERE `name` LIKE '韩%'
    -- 查询数学分>80,语文分>80的同学
    

4)使用 order by 子句查询排序结果

#升序
SELECT col_name1, col_name2, col_name3
	FROM tab_name
	ORDER BY col_name asc;
#降序
SELECT col_name1, col_name2, col_name3
	FROM tab_name;
	ORDER BY col_name desc;
  • 案例演示

    -- 演示order by使用
    -- 对数学成绩排序后输出【升序】。
    SELECT * FROM student 
    	ORDER BY math;
    	
    -- 对总分按从高到低的顺序输出 [降序] -- 使用别名排序
    SELECT `name` , (chinese + english + math) AS total_score FROM student 
    	ORDER BY total_score DESC;
    	
    -- 对姓韩的学生成绩[总分]排序输出(升序) where + order by
    SELECT `name`, (chinese + english + math) AS total_score FROM student
    	WHERE `name` LIKE '韩%'
    	ORDER BY total_score;
    

5)MySQL 表查询 —— 加强

  • 使用 where 字句

    ?如何查找 1992.1.1 后入职的员工

    SELECT ename, hiredate FROM `emp`
    	WHERE hiredate > '1992-1-1'
    

    在 mysql 中,日期类型是可以直接比较!!!

  • 如何使用 like 操作符(模糊查询)
    • %:表示 0 到 多个任意字符

    • _:表示单个任意字符
      ?如何显示首字符为 S 的员工的姓名和工资

      SELECT ename FROM emp
      	WHERE ename LIKE 'S%';
      #显示第三个字符为 O 的员工的姓名
      SELECT ename FROM emp
      	WHERE ename LIKE '__S%';
      
  • 显示出上级为 空 的员工的姓名
    SELECT DISTINCT ename FROM `emp`
    	WHERE mgr IS NULL;
    
  • 显示出表的结构
    DESC emp;
    
  • 分页查询
  • 实际开发的时候不能把符合记录的全部表返回出来,这就涉及到分页查询

    • 按照雇员的 id 号升序取出,每页显示 3 条记录,请分别显示第 1、2、3页。

    • 基本语法:

      #表示从 start 行开始取,取出 rows 行
      SELECT ... LIMIT start, rows
      
      -- 分页查询
      -- 第一页
      SELECT * FROM emp
      	ORDER BY empno
      	LIMIT 0, 3
      -- 第二页
      SELECT * FROM emp
      	ORDER BY empno
      	LIMIT 3, 3
      -- 第三页
      SELECT * FROM emp
      	ORDER BY empno
      	LIMIT 6, 3
      

      - 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • 使用 order by 字句

    • ?如何按照工资的从高到低的顺序显示雇员的信息

      SELECT * FROM emp
      	ORDER BY sal ASC;
      
    • ?按照部门号升序而雇员的工资降序排列,显示雇员信息

      SELECT * FROM emp
      	ORDER BY deptno ASC, sal DESC;
      

四、函数

1.统计函数


1)合计 / 统计函数 —— count

#返回满足条件的记录的总行数
SELECT COUNT(*) FROM tab_name
	[WHERE where_definition;]
#满足条件的某列有多少个,但是会排除为 null 的情况
SELECT COUNT(col_name) FROM tab_name
	[WHERE where_definition;]
  • 案例演示

    -- 演示mysql的统计函数的使用
    -- 统计一个班级共有多少学生?
    SELECT COUNT(*) FROM student;
    
    -- 统计数学成绩大于90的学生有多少个?
    SELECT COUNT(*) FROM student
    	WHERE math > 90
    	
    -- 统计总分大于250的人数有多少?
    SELECT COUNT(*) FROM student
    	WHERE (math + english + chinese) > 250
    	
    -- count(*) 和 count(列) 的区别 
    -- 解释 :count(*) 返回满足条件的记录的行数
    -- count(列): 统计满足条件的成员有多少个,但是会排除 为null的情况
    CREATE TABLE t15 (
    	`name` VARCHAR(20));
    INSERT INTO t15 VALUES('tom');
    INSERT INTO t15 VALUES('jack');
    INSERT INTO t15 VALUES('mary');
    INSERT INTO t15 VALUES(NULL);
    SELECT * FROM t15;
    SELECT COUNT(*) FROM t15; -- 4
    SELECT COUNT(`name`) FROM t15;-- 3
    

2)合计函数 —— sum

  • sum 函数返回满足 where 条件的行的和,一般使用在数值列
#将单个列的元素全部加起来
SELECT SUM(col_name1), SUM(col_name2), SUM(col_name3) FROM tab_name
	[WHERE where_definition]
#将多个列的元素加起来求和
SELECT SUM(clo_name1 + col_name2 + col_name3) FROM tab_name
	[WHERE where_definition]
  • 案例演示

    -- 演示sum函数的使用
    -- 统计一个班级数学总成绩?
    SELECT SUM(math) FROM student;
    
    -- 统计一个班级语文、英语、数学各科的总成绩
    SELECT SUM(math) AS math_total_score,SUM(english),SUM(chinese) FROM student;
    
    -- 统计一个班级语文、英语、数学的成绩总和
    SELECT SUM(math + english + chinese) FROM student;
    
    -- 统计一个班级语文成绩平均分
    SELECT SUM(chinese)/ COUNT(*)  FROM student;
    SELECT SUM(`name`) FROM student;
    

3)合计函数 —— avg

  • AVG 函数返回满足 WHERE 条件的一列的平均值

    SELECT AVG(col_name1), AVG(col_name2), AVG(col_name3)
    	FROM tab-name
    	[WHERE where_definition];
    
  • 案例演示

    -- 演示avg的使用
    -- 练习:
    -- 求一个班级数学平均分?
    SELECT AVG(math) FROM student;
    -- 求一个班级总分平均分
    SELECT AVG(math + english + chinese) FROM student;
    

4)合计函数 —— max / min

  • MAX / MIN 函数返回满足 WHERE 条件的一列的最大值 / 最小值

    SELECT MAX(col_name1), MAX(col_name2), MAX(col_name3) FROM tab_name
    	[WHERE where_definition];
    
  • 案例演示

    -- 演示max 和 min的使用
    -- 求班级最高分和最低分(数值范围在统计中特别有用)
    SELECT MAX(math + english + chinese), MIN(math + english + chinese) 
    	FROM student;
    
    -- 求出班级数学最高分和最低分
    SELECT MAX(math) AS math_high_socre, MIN(math)  AS math_low_socre
    	FROM student;
    

5)group by 分组子句

  • 使用 group by 子句对列进行分组

    SELECT col_name1, col_name2, col_name3 FROM tab_name
    	GROUP BY col_name;
    
  • 使用 having 字句对分组后的结果进行过滤

    SELECT col_name1, col_name2, col_name3 FROM tab_name
    	GROUP BY col_name HAVING ...;
    
  • 应用案例

    # 演示group by + having
    GROUP by用于对查询的结果分组统计, (示意图)
    -- having子句用于限制分组显示结果.
    -- ?如何显示每个部门的平均工资和最高工资
    -- 老韩分析: avg(sal) max(sal)
    -- 按照部分来分组查询
    SELECT AVG(sal), MAX(sal) , deptno 
    	FROM  emp GROUP BY deptno; 
    -- 使用数学方法,对小数点进行处理
    SELECT FORMAT(AVG(sal),2), MAX(sal) , deptno 
    	FROM  emp GROUP BY deptno; 
    
    -- ?显示每个部门的每种岗位的平均工资和最低工资
    -- 老师分析 1. 显示每个部门的平均工资和最低工资
    --          2. 显示每个部门的每种岗位的平均工资和最低工资
    SELECT AVG(sal), MIN(sal) , deptno, job 
    	FROM  emp GROUP BY deptno, job; 
    
    -- ?显示平均工资低于2000的部门号和它的平均工资 // 别名
    
    -- 老师分析 [写sql语句的思路是化繁为简,各个击破]
    -- 1. 显示各个部门的平均工资和部门号
    -- 2. 在1的结果基础上,进行过滤,保留 AVG(sal) < 2000
    -- 3. 使用别名进行过滤 
    
    SELECT AVG(sal), deptno 
    	FROM emp GROUP BY deptno
    		HAVING AVG(sal) < 2000;
    -- 使用别名		
    SELECT AVG(sal) AS avg_sal, deptno 
    	FROM emp GROUP BY deptno
    		HAVING avg_sal < 2000;	
    
    • 结果显示
      -

    • 显示的是按照分组的最低和最高工资,即按照 deptno 分组

    • GROUP BY deptno, job; 按顺序显示出来

    • ***HAVING avg_sal < 2000;***是对分组后的语句进行筛选

  • 使用分组函数和分组字句 group by
    • 显示每种岗位的雇员总数和平均工资

      SELECT COUNT(*), job, AVG(sal)
      	FROM emp
      	GROUP BY job;
      
    • 显示雇员的总数,以及获得补助的雇员数

      #COUNT 会排除字段为空的情况
      SELECT COUNT(*), COUNT(comm)
      	FROM emp
      
    • 显示经理的总人数

      SELECT COUNT(*), COUNT(IF(job = 'MANAGER',job,  NULL))
      	FROM emp
      
    • 显示雇员工资的最大差额

      SELECT (MAX(sal) - MIN(sal)) AS  max_sal_sub
      	FROM emp
      

2.字符串函数


在这里插入图片描述

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • 案例演示

    -- 演示字符串相关函数的使用  , 使用emp表来演示
    -- CHARSET(str)	返回字串字符集
    SELECT CHARSET(ename) FROM emp;
    -- CONCAT (string2  [,... ])	连接字串, 将多个列拼接成一列
    SELECT CONCAT(ename, ' 工作是 ', job) FROM emp;
    
    -- INSTR (string ,substring )	返回substring在string中出现的位置,没有返回0
    -- dual 亚元表, 系统表 可以作为测试表使用
    SELECT INSTR('hanshunping', 'ping') FROM DUAL; 
    
    -- UCASE (string2 )	转换成大写
    SELECT UCASE(ename) FROM emp;
    
    -- LCASE (string2 )	转换成小写
    
    SELECT LCASE(ename) FROM emp;
    -- LEFT (string2 ,length )	从string2中的左边起取length个字符
    -- RIGHT (string2 ,length )	从string2中的右边起取length个字符
    SELECT LEFT(ename, 2) FROM emp;
    
    -- LENGTH (string )	string长度[按照字节]
    SELECT LENGTH(ename) FROM emp;
    -- REPLACE (str ,search_str ,replace_str ) 	
    -- 在str中用replace_str替换search_str
    -- 如果是manager 就替换成 经理
    SELECT ename, REPLACE(job,'MANAGER', '经理')  FROM emp;
    
    -- STRCMP (string1 ,string2 )	逐字符比较两字串大小
    SELECT STRCMP('hsp', 'hsp') FROM DUAL;
    -- SUBSTRING (str , position  [,length ])	
    -- 从str的position开始【从1开始计算】,取length个字符
    -- 从ename 列的第一个位置开始取出2个字符
    SELECT SUBSTRING(ename, 1, 2) FROM emp;
    
    -- LTRIM (string2 ) RTRIM (string2 )  TRIM(string)
    -- 去除前端空格或后端空格
    SELECT LTRIM('  韩顺平教育') FROM DUAL;
    SELECT RTRIM('韩顺平教育   ') FROM DUAL;
    SELECT TRIM('    韩顺平教育   ') FROM DUAL;
    
    -- 练习: 以首字母小写的方式显示所有员工emp表的姓名
    -- 方法1 
    -- 思路先取出ename 的第一个字符,转成小写的
    -- 把他和后面的字符串进行拼接输出即可
    
    SELECT CONCAT(LCASE(SUBSTRING(ename,1,1)),  SUBSTRING(ename,2)) AS new_name
    	FROM emp;  
    
    SELECT CONCAT(LCASE(LEFT(ename,1)),  SUBSTRING(ename,2)) AS new_name
    	FROM emp; 
    

3.数学函数


-- 演示数学相关函数

-- ABS(num)	绝对值
SELECT ABS(-10) FROM DUAL;
-- BIN (decimal_number )十进制转二进制
SELECT BIN(10) FROM DUAL;
-- CEILING (number2 )	向上取整, 得到比num2 大的最小整数
SELECT CEILING(-1.1) FROM DUAL;

-- CONV(number2,from_base,to_base)	进制转换
-- 下面的含义是 8 是十进制的8, 转成 2进制输出
SELECT CONV(8, 10, 2) FROM DUAL;
-- 下面的含义是 8 是16进制的8, 转成 2进制输出
SELECT CONV(16, 16, 10) FROM DUAL;

-- FLOOR (number2 )	向下取整,得到比 num2 小的最大整数
SELECT FLOOR(-1.1) FROM DUAL;

-- FORMAT (number,decimal_places )	保留小数位数(四舍五入)
SELECT FORMAT(78.125458,2) FROM DUAL;
-- 结果为 78.13,,decimal_places 是保留的位数

-- HEX (DecimalNumber )	转十六进制

-- LEAST (number , number2  [,..])	求最小值
SELECT LEAST(0,1, -10, 4) FROM DUAL;
-- MOD (numerator ,denominator )	求余
SELECT MOD(10, 3) FROM DUAL;

-- RAND([seed])	RAND([seed]) 返回随机数 其范围为 0 ≤ v ≤ 1.0
-- 老韩说明
-- 1. 如果使用 rand() 每次返回不同的随机数 ,在 0 ≤ v ≤ 1.0
-- 2. 如果使用 rand(seed) 返回随机数, 范围 0 ≤ v ≤ 1.0, 如果seed不变,
--    该随机数也不变了
SELECT RAND() FROM DUAL;

SELECT CURRENT_TIMESTAMP() FROM DUAL;

-<img src="../AppData/Roaming/Typora/typora-user-images/image-style="zoom: 33%;"20230919155019071.png" alt="image-20230919155019071" style="zoom: 33%;" />

4.时间日期


外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • now 函数与 时间戳函数的区别
    • now 函数的值是不变的,时间戳的值当对标进行修改的时候会改变
-- 日期时间相关函数

-- CURRENT_DATE (  )	当前日期
SELECT CURRENT_DATE() FROM DUAL;
-- CURRENT_TIME (  )	当前时间
SELECT CURRENT_TIME()  FROM DUAL;
-- CURRENT_TIMESTAMP (  ) 当前时间戳
SELECT CURRENT_TIMESTAMP()  FROM DUAL;

-- 创建测试表 信息表
CREATE TABLE mes(
	id INT , 
	content VARCHAR(30), 
	send_time DATETIME);
	
	
-- 添加一条记录
INSERT INTO mes 
	VALUES(1, '北京新闻', CURRENT_TIMESTAMP()); 
INSERT INTO mes VALUES(2, '上海新闻', NOW());
INSERT INTO mes VALUES(3, '广州新闻', NOW());

SELECT * FROM mes;
SELECT NOW() FROM DUAL;

-- 上应用实例
-- 显示所有新闻信息,发布日期只显示 日期,不用显示时间.
SELECT id, content, DATE(send_time) 
	FROM mes;
-- 请查询在10分钟内发布的新闻, 思路一定要梳理一下.
SELECT * 
	FROM mes
	WHERE DATE_ADD(send_time, INTERVAL 10 MINUTE) >= NOW()

SELECT * 
	FROM mes
	WHERE send_time >= DATE_SUB(NOW(), INTERVAL 10 MINUTE) 

-- 请在mysql 的sql语句中求出 2011-11-11 和 1990-1-1 相差多少天
SELECT DATEDIFF('2011-11-11', '1990-01-01') FROM DUAL;
-- 请用mysql 的sql语句求出你活了多少天? [练习] 1986-11-11 出生
SELECT DATEDIFF(NOW(), '1986-11-11') FROM DUAL;
-- 如果你能活80岁,求出你还能活多少天.[练习] 1986-11-11 出生
-- 先求出活80岁 时, 是什么日期 X
-- 然后在使用 datediff(x, now()); 1986-11-11->datetime
-- INTERVAL 80 YEAR : YEAR 可以是 年月日,时分秒
-- '1986-11-11' 可以date,datetime timestamp 
SELECT DATEDIFF(DATE_ADD('1986-11-11', INTERVAL 80 YEAR), NOW()) 
	FROM DUAL;
	
SELECT TIMEDIFF('10:11:11', '06:10:10') FROM DUAL;

-- YEAR|Month|DAY| DATE (datetime )
SELECT YEAR(NOW()) FROM DUAL;
SELECT MONTH(NOW()) FROM DUAL;
SELECT DAY(NOW()) FROM DUAL;
SELECT MONTH('2013-11-10') FROM DUAL;
-- unix_timestamp() : 返回的是1970-1-1 到现在的秒数
SELECT UNIX_TIMESTAMP() FROM DUAL;
-- FROM_UNIXTIME() : 可以把一个unix_timestamp 秒数[时间戳],转成指定格式的日期
-- %Y-%m-%d 格式是规定好的,表示年月日
-- 意义:在开发中,可以存放一个整数,然后表示时间,通过FROM_UNIXTIME转换
--   
SELECT FROM_UNIXTIME(1618483484, '%Y-%m-%d') FROM DUAL;
SELECT FROM_UNIXTIME(1618483100, '%Y-%m-%d %H:%i:%s') FROM DUAL;
SELECT * FROM mysql.user \G 

5.流程控制


1)加密函数和系统函数

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

-- 演示加密函数和系统函数

-- USER()	查询用户
-- 可以查看登录到mysql的有哪些用户,以及登录的IP
SELECT USER() FROM DUAL; -- 用户@IP地址
-- DATABASE()	查询当前使用数据库名称
SELECT DATABASE();

-- MD5(str)	为字符串算出一个 MD5 32的字符串,常用(用户密码)加密
-- root 密码是 hsp -> 加密md5 -> 在数据库中存放的是加密后的密码
SELECT MD5('hsp') FROM DUAL;
SELECT LENGTH(MD5('hsp')) FROM DUAL;

-- 演示用户表,存放密码时,是md5
CREATE TABLE hsp_user
	(id INT , 
	`name` VARCHAR(32) NOT NULL DEFAULT '', 
	pwd CHAR(32) NOT NULL DEFAULT '');
INSERT INTO hsp_user 
	VALUES(100, '韩顺平', MD5('hsp'));
SELECT * FROM hsp_user; -- csdn

SELECT * FROM hsp_user  -- SQL注入问题
	WHERE `name`='韩顺平' AND pwd = MD5('hsp')  


-- PASSWORD(str) -- 加密函数, MySQL数据库的用户密码就是 PASSWORD函数加密

SELECT PASSWORD('hsp') FROM DUAL; -- 数据库的 *81220D972A52D4C51BB1C37518A2613706220DAC


-- select * from mysql.user \G 	从原文密码str 计算并返回密码字符串
-- 通常用于对mysql数据库的用户密码加密
-- mysql.user 表示 数据库.表 
SELECT * FROM mysql.user

2)流程控制语句

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

# 演示流程控制语句

# IF(expr1,expr2,expr3)	如果expr1为True ,则返回 expr2 否则返回 expr3
SELECT IF(TRUE, '北京', '上海') FROM DUAL;
# IFNULL(expr1,expr2)	如果expr1不为空NULL,则返回expr1,否则返回expr2
SELECT IFNULL( NULL, '韩顺平教育') FROM DUAL;
# SELECT CASE WHEN expr1 THEN expr2 WHEN expr3 THEN expr4 ELSE expr5 END; [类似多重分支.]
# 如果expr1 为TRUE,则返回expr2,如果expr2 为t, 返回 expr4, 否则返回 expr5

SELECT CASE 
	WHEN TRUE THEN 'jack'  -- jack
	WHEN FALSE THEN 'tom' 
	ELSE 'mary' END

-- 1. 查询emp 表, 如果 comm 是null , 则显示0.0
--    老师说明,判断是否为null 要使用 is null, 判断不为空 使用 is not
SELECT ename, IF(comm IS NULL , 0.0, comm)
	FROM emp;
SELECT ename, IFNULL(comm, 0.0)
	FROM emp;
-- 2. 如果emp 表的 job 是 CLERK 则显示 职员, 如果是 MANAGER 则显示经理
--     如果是 SALESMAN 则显示 销售人员,其它正常显示

SELECT ename, (SELECT CASE 
		WHEN job = 'CLERK' THEN '职员' 
		WHEN job = 'MANAGER' THEN '经理'
		WHEN job = 'SALESMAN' THEN '销售人员' 
		ELSE job END) AS 'job'
	FROM emp; 

SELECT * FROM emp;
SELECT * FROM dept;
SELECT * FROM salgrade;

五、MySQL 查询增强及多表查询

1.MySQL 查询增强

1)使用 where 字句

?如何查找 1992.1.1 后入职的员工

SELECT ename, hiredate FROM `emp`
	WHERE hiredate > '1992-1-1'

在 mysql 中,日期类型是可以直接比较!!!

2)如何使用 like 操作符(模糊查询)

  • %:表示 0 到 多个任意字符

  • _:表示单个任意字符
    ?如何显示首字符为 S 的员工的姓名和工资

    SELECT ename FROM emp
    	WHERE ename LIKE 'S%';
    #显示第三个字符为 O 的员工的姓名
    SELECT ename FROM emp
    	WHERE ename LIKE '__S%';
    

3)显示出上级为 空 的员工的姓名

SELECT DISTINCT ename FROM `emp`
	WHERE mgr IS NULL;

4)显示出表的结构

DESC emp;

5)分页查询

  • 实际开发的时候不能把符合记录的全部表返回出来,这就涉及到分页查询

    • 按照雇员的 id 号升序取出,每页显示 3 条记录,请分别显示第 1、2、3页。

    • 基本语法:

      #表示从 start 行开始取,取出 rows 行
      SELECT ... LIMIT start, rows
      
      -- 分页查询
      -- 第一页
      SELECT * FROM emp
      	ORDER BY empno
      	LIMIT 0, 3
      -- 第二页
      SELECT * FROM emp
      	ORDER BY empno
      	LIMIT 3, 3
      -- 第三页
      SELECT * FROM emp
      	ORDER BY empno
      	LIMIT 6, 3
      
      • 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

6)多子句查询——数据分组的总结

  • 如果 SELECT 语句同时包含有 group, by, having, order by, limit 那么他们的顺序就是上面所列出来的顺序
    • 应用案例:请统计各部门的平均工资,并且是大于 1000 的,并且按照平均工资从高到底排序

7)MySQL 多表查询

#先看这样一段代码
SELECT * 
	FROM emp, dept;

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • 在默认情况下,当两个表查询的时候规则为
    1. 从第一张表中,取出一行 和 第二张表中的每一行进行组合,返回结果
    2. 一共返回的记录数 = 第一行表行数 * 第二行表的行数
    3. 这样的多表查询返回的结果,称为笛卡尔集
    4. 解决这个问题的关键就是要写出正确的过滤条件 WHERE

8)自连接

自连接是在同一张表的链接查询

select worker.ename, boss.ename
	FROM emp worker, emp boss
	WHERE worker.mgr = boss.empno
  • 运用了自连接
    1. 把同一张表当成两张表使用
    2. 需要给表取别名: 表名 表别别名
      如:FROM emp worker, emp boss
    3. 列名不明确,可以指定列的别名

9)子查询

子查询是指嵌入在其他 sql 语句中的 select 语句,也叫嵌套查询,分为单行子查询和多行子查询。

-- 子查询的演示
-- 请思考,如何显示与 SMITH 同一部门的员工
/*
	先把查询到 SMITH 的部门号得到
	把上面的 SELECT 语句当作一个子查询来使用
*/
# 单表查询
SELECT deptno
	FROM emp
	WHERE ename = 'SMITH';
SELECT * 
	FROM emp
	WHERE deptno = (
        SELECT deptno
        FROM emp
        WHERE ename = 'SMITH';
	);
-- 如何查询和部门 10 的工作相同的雇员的
-- 名字、岗位、工资、部门号,但是不含 10 号部门自己的雇员
SELECT DISTINCT *
	FROM emp
	WHERE job IN ( 
		SELECT DISTINCT job
		FROM emp
		WHERE deptno = 10
		);
-- 可以替换成下面的 any
SELECT DISTINCT ename, sal, job
		FROM emp
		WHERE job = ANY (
            SELECT DISTINCT job
                FROM emp
                WHERE deptno = 10
		)

4)显示出表的结构

DES	C emp;

5)分页查询

  • 实际开发的时候不能把符合记录的全部表返回出来,这就涉及到分页查询

    • 按照雇员的 id 号升序取出,每页显示 3 条记录,请分别显示第 1、2、3页。

    • 基本语法:

      #表示从 start 行开始取,取出 rows 行
      SELECT ... LIMIT start, rows
      
      -- 分页查询
      -- 第一页
      SELECT * FROM emp
      	ORDER BY empno
      	LIMIT 0, 3
      -- 第二页
      SELECT * FROM emp
      	ORDER BY empno
      	LIMIT 3, 3
      -- 第三页
      SELECT * FROM emp
      	ORDER BY empno
      	LIMIT 6, 3
      
      • [外链图片转存中...(img-2kWwBoLk-1695200979280)]

6)多子句查询——数据分组的总结

  • 如果 SELECT 语句同时包含有 group, by, having, order by, limit 那么他们的顺序就是上面所列出来的顺序
    • 应用案例:请统计各部门的平均工资,并且是大于 1000 的,并且按照平均工资从高到底排序

7)MySQL 多表查询

#先看这样一段代码
SELECT * 
	FROM emp, dept;

[外链图片转存中...(img-QzSAAJD0-1695200979280)]

  • 在默认情况下,当两个表查询的时候规则为
    1. 从第一张表中,取出一行 和 第二张表中的每一行进行组合,返回结果
    2. 一共返回的记录数 = 第一行表行数 * 第二行表的行数
    3. 这样的多表查询返回的结果,称为笛卡尔集
    4. 解决这个问题的关键就是要写出正确的过滤条件 WHERE

8)自连接

自连接是在同一张表的链接查询

select worker.ename, boss.ename
	FROM emp worker, emp boss
	WHERE worker.mgr = boss.empno
  • 运用了自连接
    1. 把同一张表当成两张表使用
    2. 需要给表取别名: 表名 表别别名
      如:FROM emp worker, emp boss
    3. 列名不明确,可以指定列的别名

9)子查询

子查询是指嵌入在其他 sql 语句中的 select 语句,也叫嵌套查询,分为单行子查询和多行子查询。

9)子查询

子查询是指嵌入在其他 sql 语句中的 select 语句,也叫嵌套查询,分为单行子查询和多行子查询。

-- 子查询的演示
-- 请思考,如何显示与 SMITH 同一部门的员工
/*
	先把查询到 SMITH 的部门号得到
	把上面的 SELECT 语句当作一个子查询来使用
*/
# 单表查询
SELECT deptno
	FROM emp
	WHERE ename = 'SMITH';
SELECT * 
	FROM emp
	WHERE deptno = (
        SELECT deptno
        FROM emp
        WHERE ename = 'SMITH';
	);
-- 如何查询和部门 10 的工作相同的雇员的
-- 名字、岗位、工资、部门号,但是不含 10 号部门自己的雇员
SELECT DISTINCT *
	FROM emp
	WHERE job IN ( 
		SELECT DISTINCT job
		FROM emp
		WHERE deptno = 10
		);
-- 可以替换成下面的 any
SELECT DISTINCT ename, sal, job
		FROM emp
		WHERE job = ANY (
            SELECT DISTINCT job
                FROM emp
                WHERE deptno = 10
		)

10)子查询临时表

-- 查询ecshop中各个类别中,价格最高的商品

-- 查询 商品表
-- 先得到 各个类别中,价格最高的商品 max + group by cat_id, 当做临时表
-- 把子查询当做一张临时表可以解决很多很多复杂的查询

select cat_id , max(shop_price) 
	from ecs_goods
	group by cat_id
	
	
-- 这个最后答案	
select goods_id, ecs_goods.cat_id, goods_name, shop_price 
	from (
		SELECT cat_id , MAX(shop_price) as max_price
		FROM ecs_goods
		GROUP BY cat_id
	) temp , ecs_goods
	where  temp.cat_id = ecs_goods.cat_id 
	and temp.max_price = ecs_goods.shop_price 

11)all 和 any 操作符

  • 显示工资比部门 30 所有员工的工资高的员工的姓名,工资和部门号。

    -- ALL he  ANY 的使用
    -- 请思考:显示工资比部门 30 所有员工的工资高的员工的姓名,工资和部门号
    SELECT ename, sal, deptno
    		FROM emp
    		WHERE sal > ALL(
    				SELECT sal 
    					FROM emp
    					WHERE deptno = 30
    					)
    -- 也可以这样写
    SELECT ename, sal, deptno
    		FROM emp
    		WHERE sal > (
    				SELECT MAX(sal)
    					FROM emp
    					WHERE deptno = 30
    		)
    
    • any 和 all 的用法相同,但筛选出来的是只要大于其中某一个即可,可以转换成 min 写法

12)多列子查询

  • 请思考如何查询与 SMITH 的部门和岗位完全相同的所有雇员,并且不含其本人。

  • 多行子查询指的是子查询返回的是多列

  • 注意一定处理的是多列,多行是无法处理的(加入 DISTINCT 修饰)

    SELECT * 
    	FROM emp
    	WHERE (deptno, job) = (
    		SELECT DISTINCT deptno, job
    			FROM emp
    			WHERE ename = 'SMITH'
    			)
    

13)表复制和去重

  • 自我复制数据(蠕虫复制)

    • 有时,为了对某个 sql 语句进行效率测试,我需要海量数据时,可以使用次法为表创建海量数据。

      CREATE TABLE my_tab (
      	id INT,
      	`name` VARCHAR(32),
      	sal DOUBLE,
      	job VARCHAR(32),
      	deptno INT
      );
      
      DESC my_tab
      -- 先将 emp 表中的数据插入到 my_tab 表中
      INSERT INTO my_tab
      	(id, `name`, sal, job, deptno)
      		SELECT empno, ename, sal, job, deptno
      			FROM emp;
      -- 实现自我复制
      INSERT INTO my_tab
      	SELECT * FROM my_tab;
      
  • 如何删除掉一张表中重复的数据
    -- 实现自我复制
    INSERT INTO my_tab
    	SELECT * FROM my_tab;
    	
    CREATE TABLE my_tab01 LIKE emp
    -- 构建有重复记录的表
    INSERT INTO my_tab01
    	SELECT * FROM emp;
    SELECT * FROM my_tab01;
    -- 考虑如何去重
    /*	
    		思路
    			1.先创建一张临时表,该表的结构
    			与需要去重的表一样
    			2.把需要去重的表通过 distinct 处理
    			后复制到新表中
    			3.清除掉需要去重的表的数据
    			4.将新表中的数据复制到该表中
    			5.删除掉新表
    */
    CREATE TABLE Atemp LIKE my_tab01;
    INSERT INTO Atemp
    	SELECT DISTINCT * FROM my_tab01
    DELETE FROM my_tab01
    INSERT INTO my_tab01
    	SELECT * FROM Atemp;
    DROP TABLE Atemp
    SELECT * FROM my_tab01
    

14)合并查询

有时在实际的应用中,为了合并多个 select 语句的查询的结果,可以使用集合操作符号 union

SELECT ename, sal, job FROM emp WHERE sal > 2500
SELECT ename, sal, job FROM emp WHERE job = 'MANAGER'
-- UNION ALL 就是将两个查询的结果合并,会去重
SELECT ename, sal, job FROM emp WHERE sal > 2500
UNION ALL
SELECT ename, sal, job FROM emp WHERE job = 'MANAGER'
-- 只用 UNION 的话会自动去重 

15)MySQL 表外连接

提出一个问题,前面学习的查询是利用 where 字句对两张表或者多张表,形成的笛卡尔表进行筛选,根据关联条件,显示所有匹配的记录,匹配不上的不显示。
比如:列出部门名称和这些部门的员工的名称和工作,同时要求显示出那些没有员工的部门

  • 外连接
    • 左外连接:如果左侧的表完全显示我们就说是左外连接

    • 右外连接:如果右侧的表完全显示我们就说是右外连接

    • 即使没有完全匹配的记录也会完全显示出来

      -- 显示出所有的部门的成员,并且要求将没有成员的部门也显示来
      SELECT ename,dname
      	FROM emp RIGHT JOIN dept
      	ON emp.deptno = dept.deptno
      	ORDER BY dname
      

六、MySQL 约束

约束用于确保数据库数据满足特定的商业规则,在 MySQL 中约束包括五种,分别为:not null, unique, primary key, foreign key, check

1.primary key 主键


字段名 字段类型 primary key

用于唯一的标识表行的数据,当定义主键约束后,该列不能重复

CREATE TABLE t1(
	id INT PRIMARY KEY
)
-- 修饰后该表的 id 就不能重复了

1)主键的细节讨论

  1. 主键不能重复且不能为空

  2. 一张表最多只能有一个主键,但可以是复合主键

    -- 演示复合主键的使用
    -- 添加后,只有 id 和 `name` 均相同的时候,才违反主键规则
    CREATE TABLE t1
    	(
            id INT,
            `name` VARCHAR(32),
            email VARCHAR(32),
            PRIMARY KEY (id, `name`)
        );
    
  3. 主键指定的方式有两种,
    一种是直接再字段名后面指定
    字段名 字段类型 PRIMARY KEY
    另一种是再表定义的最后写上
    PRIMARY KEY(字段名)

  4. 使用 DESC 查询表的节后,可以看到主键的情况

2.unique 唯一


当定义了唯一约束后,该列值是不能重复的

-- unique 的使用
CREATE TABLE t21 (
	id INT UNIQUE,
    name VARCHAR(32)
);
  • unique 的细节讨论
    1. 如果没有指定 NOT NULL,则 unique 字段可以有多个 null
    2. 一个表可以有多个 unique 字段
    3. 如果一个字段是 unique not null 其效果类似于主键

3.foreign key 外键


假如有一个学生表和一个班级表,班级表中有班级 id 学生表中也有班级 id 来标识这个学生的班级信息,如果我们希望学生的班级 id 必须是存在于 班级表中的,即输入的 id 均包含于班级 id 则需要使用到外键约束。

-- 外键所在的表称为本表
FOREIGN KEY(本表字段名) REFERENCES 
	主表名 (主键名或 unique 字段名);
CREATE TABLE mY_class (
	id INT PRIMARY KEY,
	`name` VARCHAR(32) NOT NULL DEFAULT ''
);
CREATE TABLE my_student (
	id INT PRIMARY KEY,
	`name` VARCHAR(32) NOT NULL DEFAULT '',
	class_id INT,
	FOREIGN KEY (class_id) REFERENCES my_class(id)
);

1)外键细节说明

  1. 外键指向的表的字段,要求是 primary key 或者是 unique。
  2. 表的类型是 innodb,这样才支持外键。
  3. 外键字段的字符类型要和主键字段的字符类型一致(长度可以不同)。
  4. 外键字段的值必须,必须在主键的字段中出现过,或者为 null (前提是外键的字段允许为 null,即为 unique 的情况)。
  5. 一旦建立主外键的关系,数据就不能随意的删除了。

4.check


用于强制行数据必须满足的条件,假定在 sal 上定义了 check 约束,并且要求 sal 列值在 1000 ~ 2000 之间如果不再 1000 到 2000 之间就会提示出错

提示

在这里插入图片描述

  • 数据不满足约束但还是生效的,可以添加进去

5.自增长


在某张表中,存在一个 id 列,我们希望在添加记录的时候,该列从 1 开始,自动的增长,怎么处理?

字段名 整型 primary key auto_increment;
添加 自增长的字段方式
insert into xxx(字段1, 字段2, ……) values(null, ‘值’, ……);
insert int xxx(字段2, ……) values (‘值’, ……);
insert int xxx values (null, ‘值’, ……);
  • 自增长的细节
    1. 一般来说自增长是和 primary key 配合使用的
    2. 自主增长也可以单独使用,但是需要配合一个 unique
    3. 自增长修饰的字段为整数型的,虽然小数也可以但是非常非常少这样使用
    4. 自增长默认从 1 开始,你也可以下命令修改
      ALTER TABLE tab_name auto_increment = xxx;

七、索引

说起提升数据库的性能,索引是最物美价廉的东西。不用加内存,不用该程序,不用调 sql,查询速度就可能提高百倍千倍。

1.索引的原理

  • 没有索引为什么会慢?
    使用索引为什么会快?形成一个索引的数据结构,比如二叉树
  • 索引的代价
    1. 磁盘占用
    2. 对 dml(update delete insert)语句的效率影响

2.索引的类型

  1. 主键索引,主键自动为索引,称为主键索引
  2. 唯一索引(unique)
  3. 普通索引(index)
  4. 全文索引
    开发中考虑使用:全文搜索 solr 和 elasticsearch

3.添加索引

-- 演示 mysql 索引的使用
-- 创建索引
CREATE TABLE t25 (
	id INT,
	`name` VARCHAR(32)
);
-- 查询表是否有缩影
SHOW INDEXES FROM t25;
-- 添加索引
-- 添加唯一索引
CREATE UNIQUE INDEX id_index ON t25;
-- 添加普通索引
CREATE INDEX id_index ON t25(id);
-- 如何选择
-- 如果某列的值,是不会重复的,则优先考虑 unique 索引,否则使用普通索引
-- 另一种添加不同索引的方法
ALTER TABLE t25 ADD INDEX id_index(id);
-- 添加主键索引
ALTER TABLE t25 ADD PRIMARY KEY(id);

4.删除索引

DROP INDEX id_index ON t25;
-- 删除所有的索引
DROP INDEX ON t25;

5.查询索引

-- 1.方式
SHOW INDEX FROM t25
-- 2.方式
SHOW INDEXEX FROM t25
-- 3.方式
SHOW KEYS FROM t25
-- 4.方式
DESC t25

6.索引小结

  1. 较为频繁的作为条件的字段可以创建索引
  2. 唯一性太差的字段不适合单独创建缩影
  3. 更新非常频繁的字段不适合创建索引
  4. 不会出现在 WHERE 中的字段不该创建索引

八、MySQL 事务

事务用于保证数据的一致性,它由一组相关的 dml 语句组成,改组的 dml 语句要么全部成功,要么全部失败。如:转账就需要用事务来处理,用以确保数据的一致性

1.事务和表


当执行事务操作时,MySQL 语句会在表上加锁,防止其他用户改表的数据,这对用户来讲非常重要

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

1)回退事务

先介绍一下保存点,保存点是事务中的点,用于取消部分事务,当结束事务的时候,会自动删除该事务所定义的所有保存点,到执行回退事务的时候,会回退到指定的点。

2)提交事务

利用 commit 语句可以提交事务,当执行了该语句后,会确认事务的变化、结束事务、删除保存点、释放锁、数据生效,当使用 commit 语句结束事务后,其它会话可以查到事务变化后的新数据。

2.事务细节讨论


  1. 如果不开始事务,默认情况下,dml 操作是自动提交的,不能回滚
  2. 如果开启一个事务,即使没有创建保存点,也可以使用回滚来回退到事务开始
  3. 在还没有提交的时候可以创建多个保存点
  4. 在事务没有提交之前选择回退到那个保存点
  5. MySQL 的事务机制需要 innodb 的引擎才可以吃用,myisam 不可以
  6. 开始一个事务 start transction 或者 set autocommit = off

3.MySQL 事务隔离的级别


1)事务隔离级别的介绍

  1. 多个连接开启各自事务操作数据空中数据库时,数据库系统要负责隔离操作,以保证各个连接中获取数据的准确性。
  2. 如果不考虑隔离性,可能会引发以下问题
    • 脏读
    • 不可重复读
    • 幻读

2)脏读和幻读

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

3)事务隔离级别

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

说明:V 是可能出现,x 是不会出现

4)代码

-- 查看当前会话的隔离级别
SELECT @@tx_isolation;
-- 查看系统当前隔离级别
SELECT @@global.tx_isolation;
-- 设置当前会话隔离级别
SET SESSION TRANSACTION ISOLATION LEVEL repeatable read
-- 设置系统当前的隔离级别
SET GLOBAL TRANSCATION ISOLATION LEVEL REPEATABLE READ;
-- mysql 默认的隔离级别是 repeatable read,一般情况下,没有特殊的要求,没必要修改,因为该级别可以满足绝大部分的项目需求

4.MySQL 事务 ACID


1)事务 ACID 的特性

  1. 原子性(Atomicity)
    原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生
  2. 一致性(Consistency)
    事务必须使数据库从一个一致性状态变换到另一个一致性状态
  3. 隔离性(Isolation)
    事务的隔离性是多个用户并发访问数据库时,数据库为每一个用户开启的事务,不能被其他事务的操作数据所感染,多个并发事务之间要相互隔离
  4. 持久性(Durability)
    持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来及时数据库发生故障也不应该对其有任何影响。

九、MySQL 表类型和存储引擎

1.MySQL表类型和存储引擎的分类


  1. MySQL表的类型由存储类型决定,主要包括 myisam,innodb,memory等。
  2. MySQL数据库主要支持六种类型,分别是 CSV,Memory, ARCHIVE,
    MRG_MYISAM, MYISAM, InnoBDB
  3. 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

2.主要存储类型/表类型的特点


外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

3.细节说明


外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

-- 表类型和存储引擎

-- 查看所有的存储引擎
SHOW ENGINES
-- innodb 存储引擎,是前面使用过.
-- 1. 支持事务 2. 支持外键 3. 支持行级锁

-- myisam 存储引擎
CREATE TABLE t28 (
	id INT,
	`name` VARCHAR(32)) ENGINE MYISAM
-- 1. 添加速度快 2. 不支持外键和事务 3. 支持表级锁

START TRANSACTION;
SAVEPOINT t1
INSERT INTO t28 VALUES(1, 'jack');
SELECT * FROM t28;
ROLLBACK TO t1

-- memory 存储引擎
-- 1. 数据存储在内存中[关闭了Mysql服务,数据丢失, 但是表结构还在] 
-- 2. 执行速度很快(没有IO读写) 3. 默认支持索引(hash表)

CREATE TABLE t29 (
	id INT,
	`name` VARCHAR(32)) ENGINE MEMORY
DESC t29
INSERT INTO t29
	VALUES(1,'tom'), (2,'jack'), (3, 'hsp');
SELECT * FROM t29

-- 指令修改存储引擎
ALTER TABLE `t29` ENGINE = INNODB

4.如何选择表的存储引擎


1)细节说明

  1. 如果你的应用不需要事务,处理的只是基本的 CRUD 操作,那么 MyISAM 是不二的选择,速度快
  2. 如果还需要支持事务,就选择 InnoDB
  3. Memory 存储引擎就是将数据存储在内存中,由于没有磁盘的等待,速度极快,但是由于是内存的存储引擎,所做的任何修改在服务器重启后都将小时,经典的用法:用户的在线状态
    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

1)修改存储引擎

ALATER TABLE `表名` ENGINE = 存储引擎;

十、视图

看一个需求:emp 表的列的信息很多,有些信息是个人的重要信息,如果我们希望这些重要信息无法被人查询到,有什么办法?

1.视图的基本概念


  1. 视图是一个虚拟表,其内容由查询定义。同真实的表一样,试图包含列,其数据来自对应的真实表。

  2. 视图和基表的关系示意图

2.视图的基本使用


-- 创建视图
CREATE VIEW 视图名 AS SELECT语句
-- 修改视图
ALTER VIEW 视图名 AS SELECT语句
-- 展示视图的创建信息
SHOW CREATE VIEW 视图名
-- 删除视图
DROP VIEW 视图名1,视图名2
-- 视图的使用
-- 创建一个视图emp_view01,只能查询emp表的(empno、ename, job 和 deptno ) 信息

-- 创建视图
CREATE VIEW emp_view01
	AS
	SELECT empno, ename, job, deptno FROM emp; 

-- 查看视图
DESC emp_view01

SELECT * FROM emp_view01;
SELECT empno, job  FROM emp_view01;

-- 查看创建视图的指令
SHOW CREATE VIEW emp_view01
-- 删除视图
DROP VIEW emp_view01;

1)视图使用的细节

  1. 创建视图后,到数据库去看,对应视图只有一个视图结构文件,后缀为 .frm
  2. 视图的数据变化会影响到基表,基表的数据变化也会影响到视图
-- 视图的细节

-- 1. 创建视图后,到数据库去看,对应视图只有一个视图结构文件(形式: 视图名.frm) 
-- 2. 视图的数据变化会影响到基表,基表的数据变化也会影响到视图[insert update delete ]

-- 修改视图 会影响到基表

UPDATE emp_view01 
	SET job = 'MANAGER' 
	WHERE empno = 7369
	
SELECT * FROM emp; -- 查询基表


SELECT * FROM emp_view01

-- 修改基本表, 会影响到视图

UPDATE emp 
	SET job = 'SALESMAN' 
	WHERE empno = 7369

-- 3. 视图中可以再使用视图 , 比如从emp_view01 视图中,选出empno,和ename做出新视图
DESC emp_view01

CREATE VIEW emp_view02
	AS
	SELECT empno, ename FROM emp_view01
	
SELECT * FROM emp_view02

3.视图的最佳实践


外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

-- 视图的课堂练习
-- 针对 emp ,dept , 和   salgrade 张三表.创建一个视图 emp_view03,
-- 可以显示雇员编号,雇员名,雇员部门名称和 薪水级别[即使用三张表,构建一个视图]

/*
	分析: 使用三表联合查询,得到结果
	将得到的结果,构建成视图
	  
*/
CREATE VIEW emp_view03
	AS
	SELECT empno, ename, dname, grade
	FROM emp, dept, salgrade
	WHERE emp.deptno = dept.deptno AND 
	(sal BETWEEN losal AND hisal) 

DESC emp_view03
SELECT * FROM emp_view03

十一、MySQL 管理

1.MySQL 用户


MySQL 中的所有用户,都存储在系统数据库 mysql 中的 user 表中

1)对 user 表中重要字段的说明

  1. host:允许登录的位置,localhost 表示该用户只允许本地登录,也可以指定 ip 地址
  2. user:用户名
  3. authentic_string:密码,是通过 mysql 的 password( ) 函数加密之后的密码

2)创建用户

#创建用户并同时指定密码
CREATE user '用户名' @'允许登录的位置' identified by '密码'

3)删除用户

DROP user '用户名' @'允许登录的位置'

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

-- Mysql用户的管理
-- 原因:当我们做项目开发时,可以根据不同的开发人员,赋给他相应的Mysql操作权限
-- 所以,Mysql数据库管理人员(root), 根据需要创建不同的用户,赋给相应的权限,供人员使用

-- 1. 创建新的用户
-- 解读 (1) 'hsp_edu'@'localhost' 表示用户的完整信息 'hsp_edu' 用户名 'localhost' 登录的IP
-- (2) 123456 密码, 但是注意 存放到 mysql.user表时,是password('123456') 加密后的密码
--     *6BB4837EB74329105EE4568DDA7DC67ED2CA2AD9
CREATE USER 'hsp_edu'@'localhost' IDENTIFIED BY '123456'

SELECT `host`, `user`, authentication_string  
	FROM mysql.user

-- 2. 删除用户
DROP USER 'hsp_edu'@'localhost'

-- 3. 登录

-- root 用户修改 hsp_edu@localhost 密码, 是可以成功.
SET PASSWORD FOR 'hsp_edu'@'localhost' = PASSWORD('123456')
--  修改自己的密码, 没问题

SET PASSWORD = PASSWORD('abcdef')

-- 修改其他人的密码, 需要权限

SET PASSWORD FOR 'root'@'localhost' = PASSWORD('123456')

2.MySQL 权限


外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

1)给用户授权

GRANT 权限列表 ON.对象名 TO '用户名'@'登陆位置' identified by '密码'

说明:

  1. 权限列表,多个权限用逗号隔开
    grant select on ……
    grant select, delete, create on ……
    grant all 权限 on 表示赋予该用户在该对象上的所有权限

  2. 特别说明

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  3. identified by 可以省略,也可以写出

    • 如果用户存在,就是修改用户的密码
    • 如果该用户不存在,就是创建用户

2)回收用户授权

REVOKE 权限列表 ON 库.对象名 FROM '用户名'@'登陆位置'

3)权限生效指令

-- 如果权限没有生效,可以执行下面的指令
FLUSH PRIVILEGES;
-- 演示 用户权限的管理

-- 创建用户 shunping  密码 123 , 从本地登录
CREATE USER 'shunping'@'localhost' IDENTIFIED BY '123'

-- 使用root 用户创建 testdb  ,表 news
CREATE DATABASE testdb
CREATE TABLE news (
	id INT ,
	content VARCHAR(32));
-- 添加一条测试数据
INSERT INTO news VALUES(100, '北京新闻');
SELECT * FROM news;

-- 给 shunping 分配查看 news 表和 添加news的权限
GRANT SELECT , INSERT 
	ON testdb.news
	TO 'shunping'@'localhost'
	
-- 可以增加update权限
GRANT UPDATE  
	ON testdb.news
	TO 'shunping'@'localhost'
	
	
-- 修改 shunping的密码为 abc
SET PASSWORD FOR 'shunping'@'localhost' = PASSWORD('abc');

-- 回收 shunping 用户在 testdb.news 表的所有权限
REVOKE SELECT , UPDATE, INSERT ON testdb.news FROM 'shunping'@'localhost'
REVOKE ALL ON testdb.news FROM 'shunping'@'localhost'

-- 删除 shunping
DROP USER 'shunping'@'localhost'

4)MySQL 管理细节

  1. 在创建用户的适合,如果不指定 Host,则为 %,%表示所有的 IP 都有连接权限,
  2. 你也可以这样指定
    create user ‘xxx’@‘192.318.1.%’ 表示该用户在 这样的 ip 下是可以登录 MySQL 的
  3. 在删除的用户时,如果 host 不是 %,需要明确指定 ‘用户’@‘host值’
  • 7
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

*Soo_Young*

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值