MySQL学习全内容

MySQL

1.数据库的分类

关系型数据库:(SQL)

  • MySQL,Oracle,Sql Server, DB2,SQLlite

  • 通过表和表之间,行和列之间的关系进行数据的存储,学员表信息,考勤表

非关系型数据库:(NoSQL)

  • Redis,MongDB

  • 非关系型数据库,对象存储,通过对象的自身属性来决定

DBMS(数据库管理系统)

  • 数据库的管理软件,科学有效的管理我们的数据,维护和获取数据;

  • MySQL本质上就是数据库管理系统

2.操作数据库(了解)

1.创建数据库

CREATE DATABASE [IF NOT EXISTS] westos;

2.删除数据库

DROP DATABASE [IF NOT EXISTS] westos;

3.使用数据库

USE school

4.查看数据库

SHOW DATABASE --查看所有数据库

3.数据库的列类型

数值

  • tinyint 十分小的数据 1个字节[有符号-128~127;无符号0~255]

  • smallint 较小的数据 2个字节

  • mediumint 中等大小的整数 3个字节

  • int 标准的整数 4个字节 常用的

  • bigint 较大的数据 8个字节

  • float 浮点数 4个字节

  • double 浮点数 8个字节 (精度问题)

  • decimal 字符串形式的浮点数 金融计算的时候一般使用

字符串、文本、二进制类型

  • char 字符串 固定大小 0~255

  • varchar 可变字符串 0~65535

  • tinytext 微型文本 2^8 - 1

  • text 文本串 2^16 - 1

  • longtext 长文本串 2^32 - 1

  • blob 二进制数据类型 2^16 - 1

  • longblob 二进制数据类型 2^32 - 1

时间日期

java.util.Data

  • date YYYY-MM-DD 日期格式

  • time HH:mm:ss 事件格式

  • datetime YYYY-MM-DD HH:mm:ss 最常用时间格式

  • timestamp 时间戳 1970.1.1 到现在的毫秒数

  • year 年份表示

null

  • 没有值 ,未知

  • ==注意,不要使用NULL进行运算,结果为NULL

4.数据库的字段属性(重点)

Unsigned:

  • 无符号的整数

  • 声明了该列不能为附属

zerofill:

  • 0填充的

  • 不足的位数,使用0来填充

自增:

  • 通常理解为自增,自动在上一条记录的基础上+1(默认)

  • 通常用来设计唯一的主键 index,必须是整数类型

  • 可以自定义设计主键自增的起始值和步长

非空 NULL not null

  • 假设设置为 not null,如果不给他赋值,就会报错

  • NULL,如果不填写值,默认就是null

默认:

  • 设置默认的值!

  • sex,默认值为男,如果不指定该列的值,则会有默认的值

扩展

/*每一个表,都必须存在以下五个字段,未来做项目用的,表示一个记录存在的意义*/
id 主键
verson 乐观锁
id_delete 伪删除
gmt_create 创建时间
gmt_update 修改事件

5.Mysql三层结构

简单来说一个指令首先打入到3306端口,然后传递到DBMS,DBMS进行解读后,找到要操作的对应的数据库及表,操作完成后再返回命令终端

SQL语句分类

DDL:数据定义语句[创建表,库]

DML:数据操作语句(增删改查)

DQL:数据查询语句[select]

DCL:数据控制语句[管理数据库 grand revoke]

6.Java操作MySQL

public class JavaMysql {
    public static void main(String[] args) throws ClassNotFoundException, SQLException {
        //如何用Java来操作Mysql
​
        //加载类,得到mysql连接
        Class.forName("com.mysql.jdbc.Driver");
        Connection connection = DriverManager.getConnection("jdbc.mysql://localhost:3306");
​
        //创建一个商品hsp_goods表,选用适当的数据类型
        //添加2条数据
        //删除表goods
​
        //这里可以编写sql
        String sql = "create table hsp_goods (id int,name varchar(32),price double,introduce text)";
​
        //得到statement对象,把sql 语句发送给mysql执行
        Statement statement = connection.createStatement();
        statement.executeUpdate(sql);
    }
}
​

7.创建数据库

CREATE DATABASE [IF NOT EXISTS] db_name
--如果不写if not exists,若存在表则会报错
[DEFAULT]CHARACTER SET charset_name
[DEFAULT]COLLATE collation_name

1.CHARACTER SET:指定数据库采用的字符集,默认为utf8

2.COLLATE:指定数据库字符集校对规则(常用的 utf8_bin[区分大小写];utf8_general_ci[不区分大小写])默认用ci

例如:创建一个使用utf8字符集并带校对规则的的db02数据库

在创建数据库时,为了规避关键字,可以打上反引号``

CREATE DATABASE db02 CHARACTER SET utf8 COLLATE utf8_bin

8.查询数据库

显示数据库语句

SHOW DATABASES

显示数据库创建语句

SHOW CREATE DATAVASE db_name

数据库删除语句[一定要慎用]

DROP DATABASE [IF EXISTS] db_name

9.备份恢复数据库

备份数据库(在DOS执行)

mysqldump -u 用户名 -p -B 数据库1 数据库2 数据库3 >文件名.sql

恢复数据库(注意:进入Mysql命令行再执行)

Source 文件名.sql

第二个恢复方法:直接将文件的内容放到查询编辑器中,执行

备份库的表

mysqldump -u 用户名 -p 数据库 表1 表2 表n > d:\\文件名.sql

注意:如果写了-B,会默认后面的表都为数据库,导致存储错误

10.创建表

CREATE TABLE table_name
(
     field1 datatype,
     field2 datatype,
     field3 datatype,
)character set 字符集 collate 校对规则 engine 引擎

field:指定列名

datatype:指定列类型(字段类型)

character set 如不指定,则为所在数据库字符集

collate 如不指定,则为所在数据库校对规则

11.列类型之整形

12.列类型之bit

255按二进制来算刚好8个1,可以存储进去

默认是BIT(1)也就是存储0~64

13.列类型之小数

数值型(小数)的基本使用

1.FLOAT/DOUBLE [UNSIGNED]

Float是单精度,Double是双精度

2.DECIMAL[M,D] [UNSIGNED]

  • 可以支持更加精确的小数位,M是小数位数(精度)的总数,D是(标度)小数点后面的位数

  • 如果D是0,则值没有小数点或分数部分。M最大是65,D最大是30。如果D被省略,默认是0。如果M被省略,默认是10

以上是三个小数类型的存放结果

13.列类型之字符串

字符串的基本使用

  • CHAR(size)

    固定长度字符串 最大255字符

  • VARCHAR(size)

可变长度字符串 最大65532字节 【utf8编码最大21844字符 1~3个字节用于记录大小;GBK的话用2个字符记录大小,即(65535-3)%2=32766】

细节1:

1.char(4) //这里的4表示字符数(最大255),不是字节数,不管中文还是字母都是放四个,按字符计算

2.varchar(4) //这个4表示字符数,不管是字母还是中文都已定义好的表的编码来存放数据(占用多少字节,取决于你的编码)

细节2:

char(4)是定长,就是说,即使你插入”aa“,也会占用分配的四个字符

varchar(4)是变长,就是说,如果你插入了”aa“,实际占用并不是4个字符,二十按照实际占用空间来分配(varchar本身需要1~3个字节来记录存放内容长度)

细节3:

什么时候用char,什么时候用varchar

1.如果数据是定长,推荐用char,比如md5加密的密码,邮编,手机号,身份证号等 char(32)

2.如果一个字段的长度是不确定的用varchar,比如留言,文章

查询速度:char>varchar

细节4:

14.列类型之日期类型

日期类型的基本使用

CREATE TABLE birthday6

(t1 DATE,t2 DATETIME,

t3 TIMESTAMP NOT NULL DEFAULT

CURRENT_TIMESTAMP ON UPDATE

CURRENT_TIMESTAMP );timestamp时间戳

mysql>INSERT INTO birthday (t1,t2)

VALUES('2022-11-11','2022-11-11 10:10:10');

TimeStamp在insert和update时,自动更新

演示如下:

15.创建表练习

16.修改表

17.Insert的基本使用

基本使用

INSERT INTO table_name[(culumn [,column...])]
VALUES (value [,value...])

具体如图

注意事项

  • 插入的数据应与字段的数据类型相同,否则报错

  • 数据的长度应在列的规定范围内

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

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

  • 列可以插入空值[前提是允许为空] insert into table value(null)

  • insert into tab name (列名...)value (),(),()形式添加多条记录

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

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

想指定默认值的话,在创建表的时候写DEFAULT

18.update语句

UPDATE tbl_name
       STE col_name1=expr1 [col_name2=expr2...]
       [WHERE where_definition]

如果不带WHERE语句,会修改全部语句

使用细节

  • UPDATE语句可以用新值更新原有表行中的各列

  • SET语句指示要修改那些列和要给予那些值

  • WHERE语句指定应更新哪些行,如果没有WHERE语句,则更新所有行

  • 如果需要修改多个字段,可以通过 set字段1=值1,字段2=值2

19.delete语句

delete from tb1_name
       [WHERE where_definition]

使用细节

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

  • Delete语句不能删除某一列的值(可使用update 设置为null或者'')

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

20.select语句(最重要)

SELECT使用表达式对查询的列进行运算

SELECT *|{column1|expression,column2|expression,..}
           FROM tablename;

也可以使用as语句

SELECT columnname as 别名 from 表名;

在WHERE子句中经常使用的运算符

比较运算符IN的用处

order by 子句排序查询结果

SELECT column1,column2,column3...
       FROM table;
       order by column asc|desc .....
  1. Order by 指定排序的列,排序的列既可以是表中的列名,也可以是select语句后指定的列名

  2. Asc升序[默认] Desc[降序]

  3. ORDER BY 子句应位于SELECT语句的结尾

21.合计/统计函数

Count返回行的总数

Select count(*)|count(列名) from tablename 
      [WHERE where_definition]

count * from会导致即使有空值也会计算,因为它计算的是有存入数据的

但是count * from 列 就不会出现这种情况

合计函数 -sum

Sum函数返回满足where条件的行的和 一般使用在数值列

SELECT SUM(列名) {SUM(列名)...} FROM tablename
      [WHERE where_definition]

总结

Count更多是用在统计人数,数量上面

Sum更多用在统计总和,统计数值上面

合计函数 -Max/Min

Max/Min函数返回满足where条件的一列的最大/最小值

SELECT MAX(列名) FROM tablename
      [WHERE where_definition]

合计函数 -Avg

SELECT AVG(列名) {AVG(列名)...} FROM tablename
       [WHERE where_definition]

22.分组统计

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

SELECT column1,column2,columu3..  FROM table
     GROUP BY column

使用having 子句对分组后的结果进行过滤

SELECT column1,column2,column3... 
    FROM table
    GROUP BY column HAVING ...

计算薪资小于2000的部门号和他的平均工资

使用别名不需要进行第二次计算,效率更快

23.字符串函数

标红的就是常用的

  • CONCAT

连接字符串,将多个列拼接成一个列

SELECT CONCAT(ename,`工作是`,job) FROM emp;

最终效果:

  • INSTR 其中DUAL是系统自带的一个表,可以用来测试(亚元表

SELECT INSTR('hanshunping',‘ping’) FROM DUAL;

代表‘ping’在字符中第八个出现

  • UCASE 转换成大写

SELECT UCASE(ename) FROM emp;

将这一列的所有文字都转换成大写

  • REPLACE

SELECT ename,REPLACE(job,'MANAGER','经理') FROM emp;

如果是查询到是MANAGER就替换成经理

  • SUBSTRING

SELECT SUBSTRING(ename,1,2) FROM emp;

从ename列的第一个位置开始取出2个字符

练习题以及练习效果

24.数学函数

  • CONV

SELECT CONV(8,10,2) FROM DUAL;

认为8是10进制,将其转换为2进制

  • FORMAT

SELECT FORMAT(78.123443,2) FROM DUAL;

会对数字进行四舍五入保留两位小数

  • RAND

如果使用rand每次都会返回随机数字,加入了seed后,seed不变,值就不会便

25.日期函数

那么显示时间的意义呢?

如图,可以在存入数据的时候,顺便存入时间

时间日期相关函数

--显示所有新闻信息,发布日期只显示日期,不显示时间
 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 DATE_SUB(NOW(),INTERVAL 10 MINUTE)<=send_time
--请用mysql的sql语句中求出2011-11-11和1990-1-1 相差多少天
 SELECT DATEDIFF('2011-11-11','1990-1-1') FROM DUAL;
--请用mysql的sql语句求出你活了多少天
 SELECT DATEDIFF(NOW(),'2004-4-26') FROM DUAL;
--如果你能活100岁,求出你还能活多少天
 SELECT DATEDIFF( DATE_ADD('2004-4-26',INTERVAL 100 YEAR),
     NOW()) FROM DUAL;
​

以上函数的细节说明

  1. DATE_ADD()中的 interval 后面可以是 year minute second day等

  2. DATE_SUB()中的 interval 后面可以是 year minute second day等

  3. DATEDIFF(date1,date2)得到的是天数,而且是date1-date2的天数,因此可以得到负数

  4. 这四个函数的日期类型可以是date,datetime 或者timestamp

--YEAR|MONTH|DAY|DATE(datetime)

SELECT YEAR(NOW()) FROM DUAL;
SELECT MONTH(NOW()) FROM DUAL;
SELECT DAY(2023-1-4) FROM DUAL;

--unix_timestamp()返回的是1970-1-1到现在的秒数

SELECT UNIX_TIMESTAMP() FROM DUAL;

--FROM_UNIXTIME()可以把一个nuix_timestamp 秒数,转成指定格式的日期

SELECT FROM_UNIXTIME(1618483484,'%Y-%M-%D') FROM DUAL;

意义:在开发中,可以存放一个整数,然后表示时间,通过这个函数进行转换

26.加密函数

--USER()查询用户
 SELECT USER() FROM DUAL;  --用户@IP地址
--MD5(str) 为字符串算出一个MD5 32的字符串,常用(用户密码)加密
 SELECT MD5('ZKW') FROM DUAL;
 SELECT *
    FROM user WHERE `name`='ZWK' AND pwd = MD5('ZKW')
--PASSWORD(str) --加密函数,MySQL数据库的用户密码就是用这个加密
 SELECT PASSWORD('ZKW') FROM DUAL

MD5加密的密码,无论输入多少,都是32位的

27.流程控制函数

#IF(expr1,expr2,expr3) 如果expr1为Ture,则返回expr2,反之expr3
SELECT IF(TRUE,'北京','上海') FROM DUAL;
#IFNULL(expr1,expr2) 如果expr1不为空,则返回expr1,反之expr2
SELECT IFUNLL(NULL,'张柯威') FROM DUAL;
#SELECT CASE WHEN expr1 THEN expr2 WHEN expr3 THEN expr4 ELSE expr5 EMD; 如果expr1为T,则返回expr2,如果expr3为T,返回expr4,否则返回expr5
SELECT CASE 
      WHEN TRUE THEN 'jack' 
      WHEN FALSE THEN 'tom' 
      ELSE 'mary' END
​
--判断为空用的是is null,不为空是is notnull
​
--1.查询emp表,如果comm是null,则显示0.0
SELECT ename,IF(comm IS NULL , 0.0 , comm)
     FROM emp;
--2.如果emp表的job是CLERK则显示职员,MANAGER 显示经理,其他正常
SELECT ename,(SELECT CASE
                 WHEN job = 'CLERK' THEN '职员'
                 WHEN job = 'MANAGER' THEN '经理'
                 ELSE job END) AS 'job',job
    FROM emp;
    

28.查询加强(多表查询)

#使用where子句 
--查询1002.1.1后入职的员工
SELECT * FROM emp
   WHERE hiredate > '1992-01-01'
#使用like操作符(模糊查询)
   --%:表示0到多个任意字符 _:表示任意单个字符
--如何侠士首字符为S的员工姓名和工资
SELECT ename,sal FROM emp
     WHERE ename LIKE 'S%'
--如何显示第三个字符为大写O的所有员工姓名和工资
SELECT enane,sal FROM emp
     WHERE ename LIKE '__O%'
--如何显示没有上级的员工
SELECT * FROM emp
   WHERE mgr IS NULL;
--查询表结构
DESC emp
#使用ORDER BY 子句
--如何按照工资从低到高,显示员工信息
SELECT * FROM emp
    ORDER BY sal ASC
--按照部门号升序,显示员工工资降序,显示员工信息
SELECT * FROM emp
    ORDER BY deptno ASC ,sal DESC
​

说明:在mysql中日期类型可以直接比较

29.分页查询

#按员工的id号升序取出,每页显示3条记录,请分别显示这三页
--第1页
SELECT * FROM emp 
   ORDER BY id
   LIMIT 0,3;
--第2页
SELECT * FROM emp 
   ORDER BY id
   LIMIT 3,3;
--第3页
SELECT * FROM emp 
   ORDER BY id
   LIMIT 6,3;
   --推导一个公式:
     SELECT * FROM emp
         ORDER BY id
         LIMIT 每页显示记录数*(第几页-1),每页显示记录数

基本语法

SELECT ... LIMIT START,ROWS
表示从start+1行开始取出,取出rows行,start从0开始计算

30.分组增强

#使用分组函数和分组句子 group by
--1.显示每种岗位的员工总数,平均工资
SELECT COUNT(*),AVG(sal),job
    FROM emp
    GROUP BY job;
--2.显示员工总数,以及获得的补助的员工数(若comm为null,则不会统计)
SELECT COUNT(*),COUNT(comm)
    FROM emp;
    --统计没有获得补助的
SELECT COUNT(*),COUNT(IF(comm IS NULL,1,NULL))
    FROM emp;
    SELECT COUNT(*),COUNT(*) - COUNT(comm)
    FROM emp;
--3.显示管理者的总人数(DISTINCT去重)
SELECT COUNT(DISTINCT mgr)
    FROM emp;
--4.显示员工工资的最大差额
SELECT MAX(sal) - MIN(sal)
    FROM emp;

31.多子句查询

#应用案例:统计各个部门的平均工资,并且是大于1000的,并且按照平均工资从高到低排序,取出前两行记录
SELECT deptno,AVG(sal) AS avg_sal
   FROM emp
   GROUP BY deptno
   HAVING avg_sal > 1000
   ORDER BY avg_sal DESC
   LIMIT 0,2

32.多表笛卡儿集(import)

--多表查询
--显示员工的名字,工资以及所在部门的名字(笛卡尔集)
SELECT ename,sal,dname,emp.deptno(查询固定的)
   FROM emp,dept
   WHERE emp.deptno = dept.deptno
--如何显示部门号为10的部门名,员工名和工资
SELECT dname,ename,sal
   FROM emp,dept
   WHERE emp.deptno = 10
--显示各个员工的姓名,工资,及其工资的级别
SELECT ename,sal,grade
   FROM emp,salgrade
   WHERE sal BETWEEN losal AND hisal;

SELECT*FROM emp,dept

在默认情况下:当两个表查询时,规则:

  1. 从第一张表中,取出每一行和第二张表的每一行进行组合,返回这个结果

  2. 一共返回的记录数,第一张表的行数乘以第二张的记录

  3. 这压根多表查询默认处理返回的结果,称为笛卡尔集

  4. 解决这个多表的关键就是要写出正确的过滤条件where,需要程序员分析

夺标查询的条件不能少于表的个数-1

33.多表查询(import)

^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

34.自连接

自连接是指在同一张表的连接查询[将同一张表看作两张表]

利用别名

#显示公司员工和他上级的名字
SELECT worker.ename AS '职员名',boss.ename AS '上'
  FROM emp worker,emp boss
  WHERE worker.mgr = boss.empno;
SELECT 

35.多行子查询

  • 单行子查询

    单行子查询是指只返回一行数据的子查询语句

  • 多行子查询

多行子查询指返回多行数据的子查询 使用关键字in

单行子查询案例

--如何显示与SMITH同一部门的所有员工
SELECT deptno
   FROM emp
   WHERE ename = 'SMITH'
 //获取了SMITH的编号 然后查询与他一个部门的编号
 SELECT * 
    FROM emp
    WHERE deptno = (
        SELECT deptno
        FROM emp
        WHERE ename = 'SMITH';
    )

多行子查询案例

--如何查询和部门10的工作相同的员工的名字,岗位,工资,部门号,但不是汉10部门自己的雇员
SELECT DISTINCT job
   FROM emp
   WHERE deptno = 10;
--下面是完整语句
SELECT ename,job,sal,deptno
   FROM emp
   WHERE job IN (
       SELECT DISTINCT job
       FROM emp
       WHERE deptno = 10
   ) AND deptno != 10;

36.子查询临时表

--查询ecshop中各个类别中,价格最高的商品
   --查询 商品表
   --先得到 各个类别中,价格最高的商品max + group by cat_id当作临时表
SELECT cat_id,MAX(shop_price)
   FROM ecs_goods
   GROUP BY cat_id
   
SELECT good_id,ecs_goods.cat_id,goods_name,shio_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 = shop_price
​

37.all和any

使用all

--如何显示工资比部门30的所有员工的工资高的员工的姓名,工资和部门号
SELECT ename,sal,deptno
   FROM emp
   WHERE sal > ALL(
      SELECT sal
         FROM emp
         WHERE deptno = 30
   )

使用any

--如何显示工资比部门30的其中一个员工的工资高的员工的姓名,工资和部门号
SELECT ename,sal,deptno
   FROM emp
   WHERE sal > ANY(
      SELECT sal 
         FROM emp
         WHERE deptn = 30
   )

38.多列子查询

多列子查询则是指查询返回多个列数据的子查询的语句

--如何查询与smith的部门和岗位完全相同的所有的员工,并且不含smith本人
SELECT * 
   FROM emp
   WHERE (deptno,job) = (
       SELECT deptno,job
       FROM emp
       WHERE enmae = 'SMITH'
       )AND ename != 'SMITH'
       
  
SELECT * 
  FROM student
  WHERE(math,english,chinese) = (
    SELECT math,english,chinese
     FROM student
      WHERE ename = '宋江'
  )

39.子查询练习

--查询每个部门工资高于本部门平均工资的人的资料
​
SELECT deptno, AVG(sal) AS avg_sal
   FROM emp GROUP BY deptno
​
SELECT ename,sal,temp.avg_sal,emp.deptno
   FROM emp,(
       SELECT deptno, AVG(sal) AS avg_sal
       FROM emp 
       GROUP BY deptno
   )temp
   WHERE emp.deptno = temp.deptno AND emp.sal > temp.avg_sal
--查找每个部工资最高的人的详细资料
SELECT deptnp,MAX(sal) AS max_sal
   FROM emp GROUP BY deptno
   
SELECT ename,sal,temp.max_sal,emp.deptno
  FROM emp,(
      SELECT deptnp,MAX(sal) AS max_sal
      FROM emp 
      GROUP BY deptno
  )temp
  WHERE emp.deptno = temp.deptno AND emp.sal = temp.max_sal
--显示每个部门的信息(包括:部门名,编号,地址)和人员数量
SELECT COUNT(*), deptno 
    FROM emp
    GROUP BY deptno;
SELECT dname,dept.deptno,local,tmp.per_num AS '人数'
    FROM dept,(
      SELECT COUNT(*) AS per_num, deptno
      FROM emp
      GROUP BY deptno
    )tmp
    WHERE tmp.deptno = dept.deptno
    
    
    写法:表名.*  表示将表的所有列都显示出来

40.表复制和去重

--先创建一个表
mysql> CREATE TABLE my_tab01
    -> (id INT,
    -> `name` VARCHAR(32),
    -> job VARCHAR(32),
    -> sal DOUBLE,
    -> deptno INT);
    
--1.先把emp表的记录复制到my_tab01
 INSERT INTO my_tab01
    (id,`name`,sal,job,deptno)
    SELECT empno,ename,sal,job,deptno FROM emp;
    
--2.自我复制
INSERT INTO my_tab01
    SELECT * FROM my_tab01;
    #为了对某个sql语句进行效率测试,我们需要海量数据的时候,可以用此方法为表创建海量数据
    
#面试题:如何删除一张表中的重复记录
mysql> CREATE TABLE my_tab02 LIKE my_tab01;  创建一张结构类似的表
/*
  1.先创建一张临时表my_tmp,该表的结构和my_tab02一样
  2.把my_tmp的记录通过distinct关键字处理后,把记录复制到my_tmp
  3.清除掉my_tab02的记录
  4.把my_tmp表的记录复制到my_tab02
  5.drop掉临时表my_tmp
*/
CREATE TABLE my_tab LIKE my_tab02;
INSERT INTO my_tmp
    SELECT DISTINCT  * FROM my_tab02;
DELETE FROM my_tab02;
INSERT INTO my_tab02
    SELECT * FROM my_tmp;
SELECT * FROM my_tab02;
 

41.合并查询

union all和union

--union all 就是将两个查询结果合并,不会去重
​
SELECT ename,sal,job FROM emp WHERE sal>2500
UNION ALL
SELECT ename,sal,job FROM emp WHERE job='MANAGER'
​
--union 与union all基本一样,可以去除重复的
SELECT ename,sal,job FROM emp WHERE sal>2500
UNION
SELECT ename,sal,job FROM emp WHERE job='MANAGER'

42.外连接需求

--外连接
--列出部门名称和这些部门的员工名称和工作,同时要求显示出那些没有员工的部门
SELECT dname,ename,job
   FROM emp,dept
   WHERE emp.deptno = dept.deptno
   ORDER BY dname
   #匹配不上的数据,无法显示,这时候就需要外连接

43.左外连右外连

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

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

--使用左外连接显示所有人的成绩,如果没有成绩,也要显示姓名和id,成绩显示为空
​
SELECT `name`,stu.id,grade
  FROM stu,exam
  WHERE stud.id = exam.id;
----------------改成左连接--------------------
SELECT `name`,stu.id,grade
   FROM stu LEFT JOIN exam     表1 left join 表2
   ON stu.id = exam.id;        on后跟条件
#表1就是左表,表2就是右表
--右外连接显示所有成绩,如果没有名字,显示空
  #右边的表exam和左表没有匹配的记录,也会把右表的记录显示出来
SELECT `naem`,stu.id,grade
  FROM stu RIGHT JOIN exam
  ON stu.id = exam.id;
  

44.主键

约束有not null,unique,primary key,foreign key,check

--创建主键
 CREATE TABLE pk (
    -> id INT primary key,
    -> `name` VARCHAR(32),
    -> email VARCHAR(32));
--主键列的值是不可以重复的

注意:

  • 主键不能重复且不能为null

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

--错误的
CREATE TABLE pk (
    -> id INT primary key,
    -> `name` VARCHAR(32),primary key
    -> email VARCHAR(32));
    
--正确的(复合主键)id和name做成复合主键
CREATE TABLE pk (
    -> id INT,
    -> `name` VARCHAR(32),
    -> email VARCHAR(32)
    -> PRIMARY KEY(id,`name`));---复合主键
    #当id和name同时为主键的时候,需要id和name都相同,才会存入失败,若id相同,name不同,是可以存入的

  • 主键的指定方式有两种

    1.直接在字段名后指定:字段名 primary key

    2.在表定义最后写 primary key(列名);

  • 使用desc表名,可以看到primary key 的情况

45.unique 唯一约束

使用细节

  • 如果没有指定not null ,则unique字段可以有多个null

    INSERT INTO t21
       VALUES(NULL,'TOM','TOM@QQ.COM')
    --没有在unique后面添加not null时,是可以存入的
  • 一张表可以有多个unique字段

  • 如果一个列(字段),是unique not null 使用效果类似 primary key

46.外键介绍 foreign key

若设置外键后,在添加class_id为300的人,会添加失败

同时,设置了外键后,若要删除班级表中id为200的一行,必须要先删除学生表,也就是外键的id为200的一行,否则会失败

47.外键的使用细节

用于定义主表和从表之间的关系:外键约束要定义在从表上,主表则必须具有主键约束或是unique约束,当定义外键约束后,要求外键列数必须在主表的主键列存在或是为null

FOREIGN KEY(本表字段名) REFERENCES 主表名(主键名或unique字段名)
--创建主表
mysql> CREATE TABLE my_class (
    -> id INT PRIMARY KEY,
    -> `name` VARCHAR(32) NOT NULL DEFAULT '');
    
--创建从表
mysql> CREATE TABLE my_stu (
    -> id INT PRIMARY KEY,
    -> `name` VARCHAR(32),
    -> class_id INT,
       --加入外键元素--
    -> FOREIGN KEY (class_id) REFERENCES my_class(id));
    
--测试数据
mysql> INSERT INTO my_class
    -> VALUES(100,'java'),(200,'web');
Query OK, 2 rows affected (0.00 sec)
​
mysql> INSERT INTO my_stu
    -> VALUES(1,'tom',100),(2,'jack',200);
Query OK, 2 rows affected (0.00 sec)
Records: 2  Duplicates: 0  Warnings: 0
#添加两条学生记录都成功了
​
mysql> INSERT INTO my_stu
    -> VALUES(3,'hsp',300);
1452 - Cannot add or update a child row: a foreign key constraint fails (`db01`.`my_stu`, CONSTRAINT `my_stu_ibfk_1` FOREIGN KEY (`class_id`) REFERENCES `my_class` (`id`))
#添加id为300的失败了,因为主表里面没有id为300的
​
mysql> SELECT * FROM my_stu;
+----+------+----------+
| id | name | class_id |
+----+------+----------+
|  1 | tom  |      100 |
|  2 | jack |      200 |
+----+------+----------+
2 rows in set (0.04 sec)
#最终查询效果

小细节

  • 外键指向的表的字段,要求是primary key或者是unique

  • 表的类型是(存储引擎)innodb,这样的表才支持外键

  • 外键字段的类型要和主键字段的类型一致(长度可以不同)

  • 外键字段的值,必须在主键字段中出现过,或者为null(前提是外键字段允许为null)

    -----------------------存入失败---------------------------
    mysql> INSERT INTO my_stu
        -> VALUES(3,'hsp',300);
    1452 - Cannot add or update a child row: a foreign key constraint fails (`db01`.`my_stu`, CONSTRAINT `my_stu_ibfk_1` FOREIGN KEY (`class_id`) REFERENCES `my_class` (`id`))
    -----------------------存入成功-------------------------
    mysql> INSERT INTO my_stu
        -> VALUES(3,'ally',NULL);
    Query OK, 1 row affected (0.00 sec)
  • 一旦建立主外键关系,数据就不能随意删除了

48.check

用于强制性数据必须满足的条件

oracle 和 sql server 均支持check ,但是mysql5.7目前还不支持check,只做语法校验,但不会生效

CREATE TABLE t23
   id INT PRIMARY KEY,
   `name` VARCHAR(32),
   sex VARCHAR(6) CHECK (sex IN('man','woman')),
   sal DOUBLE CHECK (sal>1000 AND sal<2000));
#在check条件的语句中添加不符合的数据会报错

49.商店表设计

#商品表
CREATE TABLE goods (
   goods_id INT PRIMARY KEY,
   goods_name VARCHAR(32) NOT NULL DEFAULT '',
   unitprice DOUBLE NOT NULL DEFAULT 0 
    CHECK(unitprice >=1.0 AND unitprice <=9999.99),
   category INT NOT NULL DEFAULT 0,
   provider VARCHAR(32) NOT NULL DEFAULT '',
);
​
​
#客户表
CREATE TABLE customer (
   customer_id INT PRIMARY KEY,
   `name` VARCHAR(32) NOT NULL DEFAULT '',
   address VARCHAR(32) NOT NULL DEFAULT '',
   email VARCHAR(32) UNQUIE,
   sex VARCHAR(6) (sex IN('man','woman'))
    --sex ENUM('男','女') NOT NULL, --枚举类型
   card_id VARCHAR(18) UNQUIE,
);
​
#购买表
CREATE TABLE purchase(
   order_id INT PRIMARY KEY,
   customer_id INT NOT NULL DEFAULT '',
   goods_id INT NOT NULL DEFAULT 0,
   nums INT,
   FOREIGN KEY(customer_id)REFERENCES customer(customer_id),
   FOREIGN KEY(goods_id)REFERENCES goods(goods_id)
);

50.自增长

字段名 整型 primary key auto_increment
#创建一张id带自增长的表
mysql> CREATE TABLE t24 (
    -> id INT PRIMARY KEY AUTO_INCREMENT,
    -> email VARCHAR(32) NOT NULL DEFAULT '',
    -> `name` VARCHAR(32) NOT NULL DEFAULT '');
    
#此时往里添加数据
mysql> INSERT INTO t24 VALUES (NULL,'JACK@QQ.COM','JACK');
​
+----+-------------+------+
| id | email       | name |
+----+-------------+------+
|  1 | JACK@QQ.COM | JACK |
+----+-------------+------+
​
#如果此时再添加数据
mysql> INSERT INTO t24
    -> VALUES(NULL,'TOM@QQ.COM','TOM');
    #同时也可以
    mysql> INSERT INTO t24
    -> (email,`name`) VALUES('hsp@qq.com','hsp') 
    --id也会实现自增长
    
+----+-------------+------+
| id | email       | name |
+----+-------------+------+
|  1 | JACK@QQ.COM | JACK |
|  2 | TOM@QQ.COM  | TOM  |
+----+-------------+------+

自增长使用细节

  • 一般配合主键使用

  • 也可以单独使用,但需要配合一个unique

  • 自增长的修饰字段为整数类型的(也可以为小数,极少使用)

  • 自增长默认从1开始,也可以通过如下明空修改

    alter table 表名 auto_increment = xxx;

51.索引 优化速度

索引不需要加内存,不需要改程序,不用调sql,查询速度可以提高千倍百倍

#创建索引
CREATE INDEX empno_index ON emp(empno);

52.索引机制

索引的代价

  1. 磁盘占用

  2. 对dml(update delete insert)语句的效率影响

索引的原理

当没有索引的时候,会进行一下全表的扫描,所以比较慢,即使第一次就找到了该id,系统不确定下面是否还有此id,所以会继续进行全表扫描

加入了索引后,会形成二叉树,从而进行更快的比较

==]=

如果对表进行dml操作,会对索引进行维护,所以会对速度产生影响

为什么索引有这些缺点还要用索引呢?

因为项目中,select 占90%,而update,delete,insert只占10%,而且造成服务器压力的主要是大量的访问,而不是修改

53.创建索引

索引类型

  1. 主键索引

    CREATE TABLE t1(
      id INT PRIMARY KEY,  --是主键,同时也是索引,称为主键索引
      `name` VARCHAR(32)
    );

  2. 唯一索引

    CREATE TABLE t2(
      id INT UNIQUE,  --id是唯一的,同时也是索引,成为unique索引
      `name` VARCHAR(32)
    );

  3. 普通索引(用的最多)

  4. 全文索引(适用于MyISAM)开发中一般用Solr和ElasticSearch

,不使用mysql自带的全文索引

#查询表是否有索引
SHOW INDEXES FROM t25;
#添加索引
--添加主键索引
ALTER TABLE t25 ADD PRIMARY KEY(id);
--添加唯一索引  某列的值不会重复,优先考虑unique
CREATE UNIQUE INDEX id_index ON t25(id);
--添加普通索引 方法1
CREATE INDEX id_index ON t25(id);
--添加普通索引 方法2
ALTER TABLE t25 ADD INDEX id_index(id);

54.删除索引

--删除索引
DROP INDEX id_index ON t25;
--删除主键索引
ALTER TABLE t25 DROP PRIMARY KEY; --不需要查询,因为每个表只有一个主键
#查询索引
--1.方式
SHOW INDEX FROM t25;
--2.方式
SHOW INDEXES FROM t25;
--3.方式
SHOW KEYS FROM t25;
--4.方式
DESC t25  --不如以上详细
​

修改索引的话,就先删除后添加

CRETAE TABLE sportman (
  id INT,
  name VARCHAR(32),
  good VARCHAR(32)
);
CREATE INDEX id_index ON sportman(id);
ALTER sportman ADD INDEX id_index(id);

55.创建索引规则

  1. 较频繁的作为查询条件的字段应该创建索引

  2. 唯一性太差的字段,不适合单独创建索引,即使作为频繁查询条件

  3. 更新非常频繁的字段不适合创建索引

  4. 不会出现再WHERE子句中字段不该创建索引

56.事务有什么用

事务用于保证数据的一致性,它由一组相关的dml语句组成,该组的dml语句要么全部成功,要么全部失败

可以理解为:将几个语句看作一个整体,要么全成功,要么全失败

在执行事务操作的时候,mysql会在表上加锁,防止其他用户修改表的数据,这对用户来说,非常重要

57.事务的操作

#创建一张测试表
CREATE TABLE t27(
  id INT,
  `name` VARCHAR(32)
    );
#开始事务
START TRANSACTION;
#设置保存点
SAVEPOINT a;
#执行dml操作
INSERT INTO t27 VALUES(100,`tom`);
SELECT * FROM t27;
#回退到a
ROLLBACK TO a;
#直接回退到事务开始的状态
ROLLBACK;

若在a点后还设置了b点,回到a点时,会删除b点

58.事务注意事项

  1. 如果不开始事务,默认情况下,dml操作是自动提交的,不能滚回

    INSERT INTO t27 VALUES(300,'milan'); --自动提交commit 不能回滚
  2. 如果开始一个事务,你没有创建保存点,你可以执行rollback,默认就是退回到事务开始的状态

  3. 你也可以在这个事务中(还没有提交的时候),创建多个保存点

  4. 你可以在事务没有提交前,选择退回到哪个保存点

  5. mysql的事务机制需要innodb的存储引擎还可以使用,myisam不好使

  6. 开始一个事务start transaction , set autocommit=off;

59.四种隔离级别

事务隔离级别介绍

  1. 多个连接开启各自事务操作数据库中数据时,数据库系统要负责隔离操作,以保证各个连接在获取数据时的准确性

  2. 如果不考虑隔离性,可能会引发脏读,不可重复读,幻读

脏读:当一个事务读取另一个事务尚未提交的改变时,产生脏读

不可重复读:同一查询在同一事务中多次进行,由于其他提交事务所作的修改或删除,每次返回不同的结果集,此时发生不可重复读

幻读:同一查询在同一事务中多次进行,由于其他提交事务所作的插入操作,每次返回不同的结果集,此时发生幻读

加锁:当一个表被另一个客户端操作未提交时,就不会去操作此表,会卡在那里等待提交

也就是说客户端C1读取后,进行了提交操作,但是C2此时也在进行此表的操作,但并没有提交,却能看见C1提交的结果,正确的是,C2不应该看见,C2索要查询的结果受到了C1的影响。如果C2要查询10点前的数据,但是C1在10,1提交了数据,导致了C2也会查询到这个数据,这就产生了错误

60.设置隔离

#查询当前隔离级别
SELECT @@tx_isolation;
#查询系统当前隔离级别
SELECT @@global.tx_isolation;
#设置当前隔离级别
SET SESSION TRANSACTION ISOLATION LEVEL (级别)READ UNCOMMITTED
#设置系统隔离级别
SET GLOBAL TRANSACTION ISOLATION LEVEL (级别)READ UNCOMMITTED
#全局修改
找到my.ini配置文件,在最后加上
transaction-isolation = SERIALIZABLE

事务的ACID特性

  1. 原子性(Atomicity):原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生

  2. 一致性(Consistency):事务必须使数据库从一个一致性状态变换到另外一个一致性状态

  3. 隔离性(Isolation):事务的隔离性是多个用户并发访问数据库时,数据库为每一个用户开启的事务,不能被其他的事务的操作数据所干扰,多个并发事务之间要互相隔离

  4. 持久性(Durability):持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来即使数据库发生故障也不应该对其有任何影响

61.mysql表类型和存储引擎

mysql的表类型由存储引擎决定,主要包括MyISM,innoDB,Memory等

MySQL数据表主要支持六种类型:

  1. 事务安全型:innoDB

  2. 非事务安全型:CSV,Memory,ARCHIVE,MRG MYISAM,MYISAM,InnoBDB

#查看所有的存储引擎
SHOW ENGINES

Memory整个数据是在内存中的,查询速度非常快

  • InnoDB:最常用的,默认的

  • Myisam:1.添加速度快 2.不支持外键和事务 3.支持表级锁

  • Memory:1.数据存储在内存中[关闭了mysql数据就会丢失] 2.执行速度很快(没有IO读写) 3.默认支持索引(hash表)

如何选择存储引擎?

  • 如果你的应用不需要事务,处理的只是基本的CRUD操作,那么MyISAM最好,速度快

  • 如果需要支持事务,选择InnoDB

  • Memory存储引擎就是将数据存储在内存中,由于没有磁盘I./O的等待,速度极快。但由于是内存存储引擎,所做的任何修改咋子服务器重启后都将消失(经典用法 用户的在线状态

#修改存储引擎
ALTER TABLE `表名` ENGINE = 存储引擎;

62.视图原理

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

通过视图可以修改基表的数据;基表的改变,也会影响到视图的数据

63.视图使用细节

#创建视图
CREATE VIEW emp_view01
  AS 
  SELECT empno,enmae,job,deptno FROM emp;
#查看创建视图的指令
SHOW CREATE VIEW emp_view01
#删除视图
DROP VIEW emp_view01;
#视图中可以再使用视图,比如从emp_view01视图中,选出empno和ename做新的视图
CREATE VIEW emp_view02
  AS
  SELECT empno,ename FROM emp_view01;

64.视图应用实践

#针对emp,dept和salgrade三张表,创建一个视图emp_view03
#可以显示雇员编号,雇员名,雇员部门名称和薪水级别
CREATE TABLE emp_view03
  AS
  SELECT empno,ename,dname,grade
  FROM emp,dept,salgrade
  WHERE emp.deptno = dept.deptno AND
  (sal BETWEEN losal AND hisal)

65.Mysql用户管理

mysql中的用户,都存储再系统数据库mysql中user表中

其中user表的重要字段说明:

  • host:允许登录的”位置“,localhost表示该用户只允许本机登录,也可以指定ip地址,比如:192.168.1.100

  • user:用户名

  • authenticatio_string:密码,是通过mysql的password()函数加密之后的密码

#创建用户
CREATE USER '用户名' @'允许登录位置' IDENTIFIED BY '密码'
#删除用户
DROP USER '用户名' @ '允许登录位置';
#用户修改密码
SET PASSWORD = PASSWORD('密码')

66.Mysql权限管理

#基本语法
GRANT 权限列表 ON 库.对象名 TO '用户名' @ '登录位置'【IDENTIFIED BY '密码'】
--权限列表,多个权限用逗号隔开
--*.* :代表本系统中的所有数据库的所有对象
--库.*:代表某个数据库中的所有数据对象
#回收用户授权
REVOKE 权限列表 ON 库.对象名 FROM '用户名'@'登录位置';
#权限生效指令
FLUSH PRIVILEGES;

67.Mysql管理细节

#在创建用户的时候,如果不指定Host,则为%,%表示所有IP都有连接权限
CREATE USER jack,
SELECT `host`,`user` FROM mysql.user;
#你也可以这样指定 create user 'xxx'@'192.168.1.%' 表示xxx用户在192.168.1.*可以登录mysql
CREATE USER 'smith'@'192.168.1.%'
#在删除用户的时候,如果host不是%,需要明确指定 '用户'@'host值'
DROP USER jack --默认就是DROP USER 'jack'@'%'
DROP USER 'smith'@'192.168.1.%'
​

68.Mysql作业1

D是错误的,别名中间有空格,且没有引号引上,导致系统会认为别名是Annual,导致Salary无法运行

B是对的,应为判断非空不可以用不等于’<>‘,只能使用is not

3无法解释,无法排序

69.Mysql作业2

--使用简单查询语句完成
(1)显示所有部门名称
(2)显示所有雇员名以及全年收入 ,并指定列名为“年收入”
SELECT dname FROM emp;
SELECT ename,(sal + IFNULL(comm,0))*13 AS "年收入"
  FROM emp;
  #一旦奖金为空,则会导致整个年收入为空,所以加入函数判断,当奖金为0的时候,将其赋值为0
--限制查询数据
(1)显示工资超过2850的雇员姓名和工资
SELECT ename,sal 
  FROM emp;
  WHERE sal > 2850;
(2)显示工资不在1500到2850之间的所有的雇员名及工资
SELECT ename,sal
  FROM emp
  WHERE sal < 1500 OR sal > 2850;
  也可以:
  SELECT enmae,sal
  FROM emp;
  WHERE NOT (sal >= 1500 AND sal <= 2850);
(3)显示编号为7566的雇员姓名以及所在部门编号
SELECT ename,deptno 
  FROM emp
  WHERE empno = 7566;
(4)显示部门10和30中工资超过1500的雇员名及工资
SELECT ename,sal 
  FROM emp
  WHERE (deptno = 10 OR deptno = 30) AND sal >= 1500
(5)显示无管理者的雇员名及岗位
SELECT ename,job
  FROM emp
  WHERE mgr IS NULL;
--排序数据
(1)显示在1991年2月1日到1991年5月1日之间雇佣的雇员名,岗位及雇佣日期,并以雇佣日期进行排序
SELECT ename,job,hiredate
  FROM emp
  WHERE hiredate >= '1991.2.1' AND hiredate <= '1991.5.1'
  ORDER BY hiredate;
(2)显示获得补助的所有雇员名,工资及补助,并以工资降序排序
SELECT ename,sal,comm
  FROM emp
  ORDER BY sal DESC;

70.Mysql作业3

--1.选择部门30中的所有员工
SELECT * FROM emp
  WHERE deptno = 30
--2.列出所有办事员(CLERK)的姓名,编号和部门编号
SELECT ename,empno,deptno FROM emp
  WHERE job = 'CLERK';
--3.找出佣金高于薪金的员工
SELECT * FROM emp
  WHERE IFNULL(comm,0) > sal;
--4.找出雇佣金高于薪金60%的员工
SELECT * FROM emp
  WHERE IFNULL(comm,0) > (sal*0.6)
--5.找出部门10中所有经理和部门20中所有办事员的详细资料
SELECT * FROM emp
  WHERE (deptno = 10 AND job = 'MANAGER') OR
        (deptno = 20 AND job = 'CLERK')
--6.找出部门10中所有经理,部门20中所有办事员,还有既不是经理又不是办事员,但薪资大于或等于2000的所有员工的详细资料
SELECT * FROM emp
  WHERE (deptno = 10 AND job = 'MANAGER') OR 
        (deptno = 20 AND job = 'CLERK') OR
        (job !='MANAGER' AND job !='CLERK' AND sal >= 2000)
--7.找出收取佣金的员工的不同工作
SELECT DISTINCT job FROM emp
  WHERE comm IS NOT NULL;
--8.找出不收佣金或收取佣金低于100的员工
SELECT * FROM emp
  WHERE comm IS NULL OR IFNULL(comm,0) < 100;
--9.找出各月倒数第3天受雇的员(last_day可以返回当月最后一天)工
SELECT * FROM emp
  WHERE LAST_DAY(hiredate) -2 = hiredate 
--10.找出早于12年前受雇的员工
SELECT * FROM emp
  WHERE DATE_ADD(hiredate,INTERVAL 12 YEAR) < NOW();
--11.以首字母小写的方式显示所有员工的姓名
SELECT CONCAT(LCASE(SUBSTRING(ename,1,1)),SUBSTRING(ename,2))
  FROM emp
--12.显示正好为5个字符的员工的姓名
SELECT * FROM emp
  WHERE LENGTH(enmae) = 5;
  • 19
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值