零基础学MySQL

1. 零基础学MySQL

1.1 数据库简介

1.1.1 数据库三层结构

1. 所谓安装Mysql数据库,就是在主机安装一个数据库管理系统(DBMS),这个管理程序可以管理多个数据库。DBMS(database manage system)
2. 一个数据库中可以创建多个表,以保存数据(信息)。
3. 数据库管理系统(DBMS)、数据库和表的关系 如图所示:

1.1.2  数据在数据库中的存储方式

1.2 SQL语句分类

DDL: 数据定义语句 [create表,库...]
DML: 数据操作语句 [增加insert,修改update,删除delete]
DQL: 数据查询语句[select ]
DCL: 数据控制语句[管理数据库: 比如用户权限grant revoke ]

1.3 创建数据库

        1. CHARACTER SET:指定数据库采用的字符集,如果不指定字符集,默认utf8
        2. COLLATE:指定数据库字符集的校对规则(常用的utf8 bin[区分大小引]、utf8 _general_ci[不区分大小引]注意默认是utf8_general_ci)

案例练习:
1. 创建一个名称为zak_db01的数据库。
2. 创建一个使用utf8字符集的zak db02数据库
3. 创建一个使用utf8字符集,并带校对规则的zak db03数据库

#演示数据库的操作
#创建一个名称为zak_db01的数据库。#使用指令创建数据库CREATE DATABASE zak_db01;#删除数据库指令DROP DATABASE zak_db01#创建一个使用utf8字符集的hsp_db02数据库CREATE DATABASE zak_db02 CHARACTER SET utf8#创建一个使用utf8字符集,并带校对规则的hsp_db03数据库CREATE DATABASE zak_db03 CHARACTER SET utf8COLLATEutf8_bin#校对规则utf8_bin区分大小默认utf8_general_ci不区分大小写#下面是一条查询的sql,select查询*表示所有字段FROM从哪个
#WHERE从哪个字段NAME='tom'查询名字是tomSELECT *FROM t1WHERE NAME = 'tom'

1.4  查看、删除数据库

#显示数据库语句:SHOW DATABASES
#显示数据库创建语句:SHOW CREATE DATABASE db_name
#数据库删除语句[一定要慎用]:DROP DATABASE [IF EXISTS] db_name

案例练习:
1. 查看当前数据库服务器中的所有数据库
2. 查看前面创建的zak_db01数据库的定义信息
3. 删除前面创建的zak_db01数据库

#演示删除和查询数据库
#查看当前数据库服务器中的所有数据库SHOW DATABASES#查看前面创建的zak_db01数据库的定义信息SHOW CREATE DATABASE `zak_db01`#说明在创建数据库,表的时候,为了规避关键字,可以使用反引号解决
#删除前面创建的zak_db01数据库DROP DATABASE zak_db01

1.5 备份恢复数据库

备份数据库(注意:在DOS执行)命令行
        mysqldump -u用户名 -p -B 数据库1 数据库2 数据库n >文件名.sqI
恢复数据库(注意: 进入Mysql命令行再执行)
        Source文件名.sql
案例练习: database03.sql 备份 zak_db02 和 zak_db03库中的数据,并恢复

#备份, 要在Dos下执行mysqldump指令其实在mysql安装目录\bin#这个备份的文件,就是对应的sql语句mysqldump -u root -p -B zak_db02 zak_db03 > d:\\bak.sqlDROP DATABASE ecshop;#恢复数据库(注意:进入Mysql命令行再执行)source d:\\bak.sql#第二个恢复方法, 直接将 bak.sql 的内容放到查询编辑器中,执行

1.6 备份恢复数据库的表

#备份库的表
mysqldump -u 用户名 -p密码 数据库 表1 表2 表n > d:\\文件名.sql

1.7 安装 Ecshop 数据库

案例练习:

#这是一个ecshop 的数据库,包括 ecshop 所有的表,请导入到mysql数据库中[备份]#进入到mysql命令行:sourceecshop 备份文件路径
#再将ecshop 整个数据库备份到你的 d:\\ecshop.sql到dos 下 :mysqldump -u root -p -B ecshop > d:\\ecshop.sql
#将mysql 的ecshop 数据库删除, 并通过备份的d:\\ecshop.sql恢复
#进入mysql命令行source d:\\ecshop.sql

1.8 创建表(按课程大纲顺序)

案例:

 #指令创建表
#注意:zak_db02 创建表时,要根据需保存的数据创建相应的列,并根据数据的类型定义相应的列类型。例:user表#id         整形#name       字符串  #password   字符串#birthday   日期
CREATE TABLE `user` (id INT,`name` VARCHAR(255),`password` VARCHAR(255),`birthday` DATE)CHARACTER SET utf8 COLLATE utf8_bin ENGINE INNODB

1.9 Mysql 常用数据类型(列类型)

1.9.1 数值型(整数)的基本使用

1. 说明:使用规范: 在能够满足需求的情况下,尽量选择占用空间小的

案例:

#演示整型的是一个
#使用 tinyint 来演示范围 有符号 -128~127 如果没有符号 0-255#说明:表的字符集,校验规则,存储引擎,使用默认
#1. 如果没有指定 unsinged, 则 TINYINT 就是有符号
#2. 如果指定 unsinged, 则 TINYINT 就是无符号 0-255CREATE TABLE t3(id TINYINT);CREATE TABLE t4(id TINYINT UNSIGNED);INSERT INTO t3 VALUES(127); #这是非常简单的添加语句SELECT * FROM t3INSERT INTO t4 VALUES(255);SELECT * FROM t4;

1.9.2 如何定义一个无符号的整数

create table t10 (id tinyint ); #默认是有符号的
create table t11 (id tinyint unsigned ); #无符号的

1.9.3 数值型(bit)的使用

1. 基本使用
        mysql> create table t05 (num bit(8));
        mysql>insert into t05 (1,3);
        mysql> insert into t05 values(2,65);

#演示bit类型使用
#说明
#1.bit(m)m在1-64#2.添加数据范围按照你给的位数来确定,比如m=8表示一个字节0~255#3.显示按照bit#4.查询时,仍然可以按照数来查询
CREATE TABLE t05 (num BIT(8));INSERT INTO t05 VALUES(255);SELECT * FROM t05;SELECT * FROM t05 WHERE num = 1;

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

1. FLOAT/DOUBLE  [UNSIGNED]      Float单精度精度,Double双精度.
2. DECIMAL [M,D] [UNSIGNED]
        可以支持更加精确的小数位。M是小数位数(精度)的总数,D是小数点(标度)后面的位数。
        如果D是0,则值没有小数点或分数部分。M最大65。D最大是30。如果D被省略,默认是0。如果M被省略,默认是10。
        建议: 如果希望小数的精度高,推荐使用decimal
案例:

#演示decimal类型、float、double使用
#创建表CREATE TABLE t06 (num1 FLOAT,num2 DOUBLE,num3 DECIMAL(30,20));
#添加数据INSERT INTO t06 VALUES (88.12345678912345,88.12345678912345,88.12345678912345);SELECT * FROM t06;
#decimal可以存放很大的数CREATE TABLE t07 (num DECIMAL(65));INSERT INTO t07 VALUES (8999999933338388388383838838383009338388383838383838383);SELECT * FROM t07;CREATE TABLE t08 (num BIGINT UNSIGNED)INSERT INTO t08 VALUES(8999999933338388388383838838383009338388383838383838383);SELECT * FROM t08;

1.9.5 字符串的基本使用

#演示字符串类型使用char varchar
--CHAR(size)
--固定长度字符串最大255字符
--VARCHAR(size) 0~65535字节
--可变长度字符串最大65532字节【utf8编码最大21844字符1-3个字节用于记录大小】
--如果表的编码是 utf8 varchar(size) size = (65535-3)/3=21844
--如果表的编码是gbk varchar(size) size = (65535-3)/2=32766CREATE TABLE t09 (`name` CHAR(255));
CREATE TABLE t10 (`name` VARCHAR(32766)) CHARSET gbk;DROP TABLE t10;

1.9.6 字符串使用细节

1. 细节1
  char(4) //这个4表示字符数(最大255),不是字节数,不管是中文还是字母都是放四个,按字符计算.
  varchar(4) //这个4表示字符数,不管是字母还是中文都以定义好的表的编码来存放数据
  不管是中文还是英文字母,都是最多存放4个,是按照字符来存放的.
2. 细节2
  char(4)是定长(固定的大小),就是说,即使你插入'aa',也会占用分配的4个字符的空间.
  varchar(4)是变长(变化的大小),就是说,如果你插入了'aa',实际占用空间大小并不是4个字符,而是按照实际占用空间来分配(说明: varchar本身还需要占用1-3个字节来记录存放内容长度)
        L(实际数据大小) + (1-3)字节
3. 细节3
        什么时候使用char,什么时候使用varchar
        1. 如果数据是定长,推荐使用char, 比如md5的密码,邮编,手机号,身份证号码等. char(32)
        2. 如果一个字段的长度是不确定,我们使用varchar,比如留言,文章
查询速度: char > varchar
4. 细节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('zak');SELECT * FROM t11;CREATE TABLE t12(`name` VARCHAR(4));INSERT INTO t12 VALUES('zak');INSERT INTO t12 VALUES('ab北京');SELECT * FROM t12;
#如果varchar不够用,可以考试使用mediumtext或者longtext,
#如果想简单点,可以使用直接使用textCREATE TABLE t13(content TEXT,content2 MEDIUMTEXT,content3 LONGTEXT);INSERT INTO t13 VALUES('zak', 'zak123', 'zak123456');SELECT * FROM t13;

1.9.7 日期类型的基本使用

日期类型的细节说明
TimeStamp 在 Insert 和 update时,自动更新

#演示时间相关的类型
#创建一张表,date,datetime,timestampCREATE TABLE t14(birthday DATE,--生日job_time DATE TIME,--记录年月日时分秒login_time TIMESTAMPNOTNULL DEFAULT CURRENT_TIMESTAMPONUPDATE CURRENT_TIMESTAMP); --登录时间,如果希望login_time列自动更新,需要配置SELECT * FROM t14;
INSERT INTO t14 (birthday,job_time)VALUES ('2022-11-11','2022-11-1110:10:10');--如果我们更新 t14 表的某条记录,login_time 列会自动的以当前时间进行更新

1.10 创建表练习

创建一个员工表 emp 选用适当的数据类型

CREATE TABLE `emp`(id INT,`name` VARCHAR(32),sex CHAR(1),brithday DATE,entry_date DATETIME,job VARCHAR(32),salary DOUBLE,`resume` TEXT) CHARSET utf8 COLLATE utf8_bin ENGINE INNODB;
-- 添加一条
INSERTINTO `emp`VALUES(100, '小妖怪', '男', '2000-11-11', '2010-11-10 11:11:11', '巡山的', 3000, '大王叫我来巡山');SELECT * FROM `emp`;

1.11 修改表-基本介绍

#修改表的操作练习
--员工表 emp 的上增加一个 image 列,varchar 类型(要求在resume后面)。ALTER TABLE empADD image VARCHAR(32) NOT NULLDEFAULT ''AFTER RESUMEDESC employee --显示表结构,可以查看表的所有列
--修改 job 列,使其长度为60。ALTER TABLE empMODIFY job VARCHAR(60) NOT NULL DEFAULT''
--删除sex列。ALTER TABLE empDROP sex
--表名改为 employee。RENAME TABLE emp TO employee 
--修改表的字符集为utf8ALTER TABLE employee CHARACTER SET utf8
--列名name修改为user_nameALTER TABLE employeeCHANGE `name` `user_name` VARCHAR(64) NOT NULL DEFAULT''DESC employee

1.12 数据库C[create]R[read]U[update]D[delete]语句

1.13 Insert语句

1.13.1 使用 INSERT 语句向表中插入数据。

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

1.14 update语句

1.14.1 使用update语句修改表中数据

1.14.2 基本使用

案例::在上面创建的employee表中修改表中的纪录
        1. 将所有员工薪水修改为5000元。
        2. 将姓名为小妖怪的员工薪水修改为3000元。
        3. 将老妖怪的薪水在原有基础上增加1000元。

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

1.14.3 使用细节:

1. UPDATE 语法可以用新值更新原有表行中的各列。
2. SET 子句指示要修改哪些列和要给予哪些值。
3. WHERE 子句指定应更新哪些行。如没有WHERE子句,则更新所有的行(记录),因此提醒一定小心。
4. 如果需要修改多个字段,可以通过 set 字段1=值1, 字段2=值2 ……

1.15 delete 语句

1.15.1 使用 delete 语句删除表中数据

delete from tbl_name[WHERE where_definition]

案例: 删除表中名称为’老妖怪’的记录。        删除表中所有记录。

-- delete 语句演示
-- 删除表中名称为’老妖怪’的记录。DELETE FROM employeeWHERE user_name = '老妖怪';
-- 删除表中所有记录, 提醒,一定要小心DELETE FROM employee;
-- Delete 语句不能删除某一列的值(可使用update 设为 null 或者 ")UPDATE employee SET job = ' WHERE user_name = '老妖怪';SELECT * FROM employee
-- 要删除这个表DROP TABLE employee;

1.15.2 使用细节

1. 如果不使用where子句,将删除表中所有数据。
2. Delete语句不能删除某一列的值(可使用update设为null或者' ')
3. 使用delete语句仅删除记录,不删除表本身。如要删除表,使用droptable语句。drop table 表名;

1.16 select 语句

1.16.1 基本语法

SELECT [DISTINCT] * | {column1, column2. column3. .}FROM table name;

1.16.2 注意事项

1. Select指定查询哪些列的数据。
2. column指定列名。
3. *号代表查询所有列。
4.  From指定查询哪张表。
5. DISTINCT 可选,指显示结果时,是否去掉重复数据
案例练习:
        1. 查询表中所有学生的信息。
        2. 查询表中所有学生的姓名和对应的英语成绩。
        3. 过滤表中重复数据distinct 。
        4. 要查询的记录,每个字段都相同,才会去重

--select语句【重点难点】CREATE TABLE student(id INT NOT NULL DEFAULT 1,NAME VARCHAR(20) NOT NULL DEFAULT '',chinese FLOAT NOT NULL DEFAULT 0.0,english FLOAT NOT NULL DEFAULT 0.0,math FLOAT NOT NULL DEFAULT 0.0);INSERT INTO student (id, NAME, chinese, english, math) VALUES (1,'zak',89,78,90);INSERT INTO student (id ,NAME, chinese, english, math)VALUES (2,'张飞',67,98,56);INSERT INTO student (id, NAME, chinese, english, math)VALUES (3,'宋江',87,78,77);INSERT INTO student (id, NAME, chinese, english, math)VALUES (4,'关羽',88,98,90);INSERT INTO student (id, NAME, chinese, english, math)VALUES (5,'赵云',82,84,67);INSERT INTO student (id, NAME, chinese, english, math)VALUES (6,'欧阳锋',55,85,45);INSERT INTO student (id, NAME, chinese, english, math)VALUES (7,'黄蓉',75,65,30);INSERT INTO student (id, NAME, chinese, english, math)VALUES (8,'韩信',45,65,99);SELECT * FROM student;--查询表中所有学生的信息。SELECT  *FROM student;
--查询表中所有学生的姓名和对应的英语成绩。SELECT `name`, english FROM student;
--过滤表中重复数据distinct。SELECT DISTINCT english FROM student;
--要查询的记录,每个字段都相同,才会去重SELECT DISTINCT `name`, english FROM student;

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

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

1.16.4 在select语句中可使用as语句

SELECT column_name as 别名 from 表名;

案例: 1. 统计每个学生的总分   2. 在所有学生总分加10分的情况   3. 使用别名表示学生分数。

-- select 语句的使用
-- 统计每个学生的总分SELECT `name`,(chinese + english + math) FROM student;
--在所有学生总分加10分的情况SELECT `name`,(chinese + english + math + 10) FROM student;
--使用别名表示学生分数。 SELECT `name` AS '名字', (chinese + english + math + 10) AS total_scoreFROM student;

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

1.16.6 使用where子句,进行过滤查询

案例:

-- select语句
-- 查询姓名为赵云的学生成绩SELECT * FROM studentWHERE `name` = '赵云'--查询英语成绩大于90分的同学SELECT * FROM studentWHERE english > 90-- 查询总分大于200分的所有同学SELECT  *FROM studentWHERE(chinese + english + math) > 200-- 查询math大于60 并且(and)id大于4的学生成绩SELECT * FROM studentWHERE math > 60 AND id > 4-- 查询英语成绩大于语文成绩的同学SELECT * FROM studentWHERE english > chinese-- 查询总分大于200分 并且 数学成绩小于语文成绩,的姓赵的学生.
-- 赵% 表示 名字以韩开头的就可以SELECT * FROM studentWHERE(chinese + english + math) > 200 ANDmath < chinese AND `name` LIKE '赵%'-- 查询英语分数在 80-90之间的同学。SELECT * FROM studentWHERE english >= 80 AND english <= 90;SELECT * FROM studentWHERE english BETWEEN 80 AND 90;
-- between .. and .. 是 闭区间-- 查询数学分数为 89,90,91的同学。SELECT * FROM studentWHERE math = 89 OR math = 90 OR math = 91;SELECT  *FROM studentWHERE math IN (89, 90, 91);-- 查询所有姓李的学生成绩。SELECT * FROM studentWHERE `name` LIKE '李%'

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

SELECT column1 , column2 . column3. .FROM table;order by column asc | desc, ...

1. Order by 指定排序的列,排序的列既可以是表中的列名,也可以是select语句后指定的列名。
2.  Asc升序[默认]、Desc降序
3. ORDER BY子句应位于SELECT语句的结尾。

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

1.17 合计/统计函数

1.17.1 count

-- Count返回行的总数Select count(*) | count(列名) from table_name[WHERE where_definition]
-- 演示mysql 的统计函数的使用
-- 统计一个班级共有多少学生?SELECT COUNT(*) FROM student;-- 统计数学成绩大于90的学生有多少个?SELECT COUNT(*) FROM studentWHERE math>90-- 统计总分大于250的人数有多少?SELE CTCOUNT(*) FROM studentWHERE (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; -- 4SELECT COUNT(`name`) FROM t15; -- 3-- 演示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;--演示avg的使用
--练习:
--求一个班级数学平均分?SELECT AVG (math)FROM student;--求一个班级总分平均分SELECT AVG(math + english + chinese) FROM student;--演示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_socreFROM student;

1.17.2 sum

--Sum函数返回满足where条件的行的和 -一般使用在数值列select sum(列名) { , sum(列名)...} from tablename[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;

1.17.3 avg

-- AVG函数返回满足where条件的一列的平均值Select avg(列名) {,avg(列名)...} from tablename[WHERE where_definition]
-- 演示avg的使用
-- 练习:
-- 求一个班级数学平均分?SELECT AVG(math) FROM student;-- 求一个班级总分平均分SELECT AVG(math + english + chinese) FROM student;

1.17.4 max/min

-- Max/min函数返回满足where条件的一列的最大/最小值Select max(列名)from tablename[WHERE where_definition]        
-- 演示max 和 min的使用
-- 求班级最高分和最低分(数值范围在统计中特别有用)SELECT MAX (math + english + chinese), MIN(math + english + chineseFROMstudent;--求出班级数学最高分和最低分SELECT MAX(math) AS math_high_socre,MIN(math) AS math_low_socreFROM student;

1.17.5 使用groupby子句对列进行分组[先创建测试表]

SELECT column1, column2. column3.. FROM tablegroup by column

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

SELECT column1 , column2 . column3 ..FROM tablegroup by column having ...

group by 用于对查询的结果分组统计,
having 子句用于限制分组显示结果.
        ?如何显示每个部门的平均工资和最高工资
       ?显示每个部门的每种岗位的平均工资和最低工资
       ?显示平均工资低于2000的部门号和它的平均工资 //别名

CREATE TABLE dept(/*部门表*/deptno MEDIUMINT UNSIGNED NOTNULL DEFAULT0,dname VARCHAR(20) NOTNULL DEFAULT "",loc VARCHAR(13) NOT NULL DEFAULT "");INSERT INTO dept VALUES(10, 'ACCOUNTING', 'NEWYORK'),(20, 'RESEARCH', 'DALLAS'),(30, 'SALES', 'CHICAGO'),(40, 'OPERATIONS', 'BOSTON');SELECT * FROM dept;-- 员工表CREATE TABLE emp(empno MEDIUMINT UNSIGNED NOTNULL DEFAULT 0,/*编号*/ename VARCHAR(20) NOTNULL DEFAULT "", /*名字*/job VARCHAR(9) NOTNULL DEFAULT "",/*工作*/mgr MEDIUMINT UNSIGNED,/*上级编号*/hiredate DATE NOT NULL, /*入职时间*/sal DECIMAL(7,2) NOTNULL, /*薪水*/comm DECIMAL(7,2) ,/*红利 奖金*/deptno MEDIUMINT UNSIGNED NOT NULL DEFAULT 0/*部门编号*/);-- 添加测试数据INSERTINTO empVALUES(7369, 'SMITH', 'CLERK', 7902, '1990-12-17', 800.00,NULL , 20),(7499, 'ALLEN', 'SALESMAN', 7698, '1991-2-20', 1600.00, 300.00, 30),(7521, 'WARD', 'SALESMAN', 7698, '1991-2-22', 1250.00, 500.00, 30),(7566, 'JONES', 'MANAGER', 7839, '1991-4-2', 2975.00,NULL,20),(7654, 'MARTIN', 'SALESMAN', 7698, '1991-9-28',1250.00,1400.00,30),
(7698, 'BLAKE','MANAGER', 7839,'1991-5-1', 2850.00,NULL,30),(7782, 'CLARK','MANAGER', 7839, '1991-6-9',2450.00,NULL,10),(7788, 'SCOTT','ANALYST',7566, '1997-4-19',3000.00,NULL,20),(7839, 'KING','PRESIDENT',NULL,'1991-11-17',5000.00,NULL,10),(7844, 'TURNER', 'SALESMAN',7698, '1991-9-8', 1500.00, NULL,30),(7900, 'JAMES','CLERK',7698, '1991-12-3',950.00,NULL,30),(7902, 'FORD', 'ANALYST',7566,'1991-12-3',3000.00, NULL,20),(7934,'MILLER','CLERK',7782,'1992-1-23', 1300.00, NULL,10)SELECT * FROM emp;-- 工资级别
#工资级别表
CREATETABLE salgrade(grade MEDIUMINT UNSIGNED NOTNULL DEFAULT 0,/*工资级别*/losal DECIMAL(17,2) NOTNULL, /* 该级别的最低工资 */hisal DECIMAL(17,2) NOTNULL /* 该级别的最高工资*/);INSERTINTO salgrade VALUES (1,700,1200);INSERTINTO salgrade VALUES (2,1201,1400);INSERTINTO salgrade VALUES (3,1401,2000);INSERTINTO salgrade VALUES (4,2001,3000);INSERTINTO salgrade VALUES (5,3001,9999);SELECT * FROM salgrade;SELECT * FROM dept;SELECT * FROM emp;--演示groupby+having-- GROUPby用于对查询的结果分组统计,
-- having 子句用于限制分组显示结果.
-- ? 如何显示每个部门的平均工资和最高工资
-- 分析:avg(sal) max(sal)
-- 按照部分来分组查询SELECTAVG(sal), MAX(sal) , deptnoFROM emp GROUP BY deptno;
-- 使用数学方法,对小数点进行处理SELECT FORMAT(AVG(sal),2), MAX(sal) , deptnoFROM emp GROUP BY deptno;-- ?显示每个部门的每种岗位的平均工资和最低工资
-- 分析 1. 显示每个部门的平均工资和最低工资
--     2. 显示每个部门的每种岗位的平均工资和最低工资SELECT AVG(sal), MIN(sal) , deptno, jobFROM emp GROUP BY deptno,job;-- ?显示平均工资低于2000的部门号和它的平均工资 // 别名
-- 分析 [写sql语句的思路是化繁为简,各个击破]
-- 1. 显示各个部门的平均工资和部门号
-- 2. 在1的结果基础上,进行过滤,保留 AVG(sal)<2000
-- 3. 使用别名进行过SELECT AVG (sal), deptnoFROM emp GROUP BY deptnoHAVING AVG (sal) < 2000;
-- 使用别名SELECT AVG (sal) AS avg_sal, deptnoFROM emp GROUP BY deptnoHAVING avg_sal < 2000;

1.18 字符串相关函数

-- 演示字符串相关函数的使用 , 使用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('zak', 'ke') 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('zak', 'zak') 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)
-- 去除前端空格或后端空格SELECTLTRIM('  zak')FROMDUAL;SELECTRTRIM('zak  ')FROMDUAL;SELECTTRIM('  zak  ')FROMDUAL;-- 练习: 以首字母小写的方式显示所有员工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;

1.19 数学相关函数

        rand(返回一个随机浮点值v.范围在0到1之间(即,其范围为0<= v <=1.0)。若已指定一个整数参数N, 则它被用作种子值,用来产生重复序列。

--演示数学相关函数
--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 FORM AT (78.125458,2) FROM DUAL;--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;

1.20 时间日期相关函数

        在实际开发中,我们也经常使用 int 来保存一个unix时间戳,然后使用from_unixtime()进行转换,,还是非常有实用价值的

--日期时间相关函数--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 );-- 添加一条记录INSERTINTO mesVALUES(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 mesWHERE DATE_ADD(send_time, INTERVAL 10 MINUTE) >= NOW()SELECT * FROMmesWHERE send_time >= DATE_SUB(NOW(), INTERVAL10 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
-- INTERVAL80YEAR : YEAR 可以是 年月日,时分秒
-- '1986-11-11' 可以 date,datetime timestampSELECT 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()) FROMDUAL;SELECT DAY(NOW()) FROMDUAL;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

1.21 加密和系统函数

--演示加密函数和系统函数--USER()查询用户
--可以查看登录到mysql的有哪些用户,以及登录的IPSELECT USER() FROM DUAL; --用户@IP地址
--DATABASE()查询当前使用数据库名称SELECT DATA BASE();--MD5(str)为字符串算出一个MD532的字符串,常用(用户密码)加密
--root密码是hsp->加密md5->在数据库中存放的是加密后的密码SELECT MD5('zak')FROM DUAL;SELECT LENGTH (MD5('zak')) FROM DUAL;-- 演示用户表,存放密码时,是md5CREATE TABLE zak_user(id INT ,`name` VARCHAR(32) NOT NULL DEFAULT ",pwd CHAR(32) NOTNULL DEFAULT ");INSERT INTO zak_userVALUES(100, '知昂可', MD5('zak'));SELECT * FROM zak_user;  -- csdnSELECT * FROM zak_user  -- SQL注入问题WHERE`name`='知昂可' AND pwd = MD5('zak')-- PASSWORD(str) -- 加密函数, MySQL 数据库的用户密码就是 PASSWORD函数加密SELECT PASSWORD('zak') FROM DUAL; -- select * from mysql.user \G    从原文密码str 计算并返回密码字符串
-- 通常用于对mysql数据库的用户密码加密
-- mysql.user 表示 数据库.表SELECT * FROM mysql.user

1.22 流程控制函数

#演示流程控制语句#IF(expr1,expr2,expr3)如果expr1为True,则返回expr2否则返回expr3SELECT IF (TRUE, '北京', '上海') FROM DUAL;
#IFNULL(expr1,expr2)如果expr1不为空NULL,则返回expr1,否则返回expr2SELECT IFNULL( NULL, '知昂可')FROMDUAL;
# SELE CTCASE WHEN expr1 THEN expr2 WHEN expr3 THEN expr4 ELSE expr5 END; [类似多重分支.]
# 如果expr1 为TRUE,则返回expr2,如果expr2 为t, 返回 expr4, 否则返回 expr5SELECT CASEWHEN TRUE THEN'jack' -- jackWHEN FALSE THEN'tom'ELSE 'mary' END-- 1. 查询emp 表, 如果 comm 是null, 则显示0.0
-- 说明,判断是否为null 要使用 is null, 判断不为空 使用 is notSELECT 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 CASEWHEN 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;

1.23 mysql表查询--加强

1.23.1 介绍

        在前面我们讲过mysql表的基本查询,但是都是对一张表进行的查询,这在实际的软件开发中,还远远的不够。   下面我们讲解的过程中,将使用前面创建三张表(emp,dept,salgrade)为大家演示如何进行多表查询
使用where子句
        ?如何查找1992.1.1后入职的员工
如何使用like操作符
        %:表示O到多个字符:表示单个字符
        ?如何显示首字符为S的员工姓名和工资
        ?如何显示第三个字符为大写O的所有员工的姓名和工资
如何显示没有上级的雇员的情况
使用order by子句
        ?如何按照工资的从低到高的顺序,显示雇员的信息
        ?按照部门号升序而雇员的工资降序排列,显示雇员信息

--查询加强
--使用where子句
-- ?如何查找1992.1.1后入职的员工
-- 说明:在mysql中,日期类型可以直接比较,需要注意格式SELECT * FROM empWHERE hiredate >'1992-01-01'--如何使用like操作符(模糊)
-- %: 表示0到多个任意字符 _: 表示单个任意字符
-- ?如何显示首字符为S的员工姓名和工资SELECT ename, sal FROM empWHERE ename LIKE 'S%-- ?如何显示第三个字符为大写O的所有员工的姓名和工资SELECT ename, sal FROM empWHERE ename LIKE '__O%'--如何显示没有上级的雇员的情况SELECT * FROM empWHERE mgr IS NULL;
-- 查询表结构DESC emp-- 使用order by 子句
-- ?如何按照工资的从低到高的顺序[升序],显示雇员的信息SELECT * FROM empORDER BY sal--?按照部门号升序而雇员的工资降序排列 , 显示雇员信息SELECT * FROM empORDER BY deptno ASC , sal DESC;

1.23.2 分页查询

--分页查询-
-按雇员的id号升序取出,每页显示3条记录,请分别显示第1页,第2页,第3页--第1页SELECT * FROM empORDER BY empnoLIMIT 0,3;
--第2页SELECT * FROM empORDER BY empnoLIMIT 3,3;
--第3页SELECT * FROM empORDER BY empnoLIMIT 6,3;
--推导一个公式SELECT * FROM empORDER BY empnoLIMIT  每页显示记录数 * (第几页-1),每页显示记录数
--测试SELECT job,COUNT(*)FROM emp GROUP BY job;
--显示雇员总数,以及获得补助的雇员数SELECT COUNT(*)FROM emp WHERE mgr IS NOT NULL;SELECT MAX(sal)-MIN(sal)FROM emp;

1.23.3 使用分组函数和分组子句groupby

--增强groupby的使用--(1)显示每种岗位的雇员总数、平均工资。SELECT COUNT(*),AVG(sal),jobFROM empGROUP BY job;
--(2)显示雇员总数,以及获得补助的雇员数。
--思路: 获得补助的雇员数 就是 comm 列为非null, 就是count(列),如果该列的值为null, 是不会统计 ,SQL 非常灵活,需要我们动脑筋.SELECT COUNT(*), COUNT(comm)FROM emp-- 老师的扩展要求:统计没有获得补助的雇员数SELECT COUNT(*), COUNT(IF(comm IS NULL, 1, NULL))FROM empSELECT COUNT(*), COUNT(*)- COUNT(comm)FROM emp
-- (3) 显示管理者的总人数。小技巧:尝试写->修改->尝试[正确的]SELECT COUNT (DISTINCT mgr)FROM emp;-- (4) 显示雇员工资的最大差额。
-- 思路: max(sal)-min(sal)SELECT MAX(sal)- MIN(sal)FROM emp;SELECT * FROM emp;select * from dept;-- 应用案例:请统计各个部门groupby 的平均工资 avg,
-- 并且是大于1000的 having,并且按照平均工资从高到低排序, orderby
-- 取出前两行记录 limit0,2SELECT deptno,AVG(sal) AS avg_salFROM empGROUP BY deptnoHAVING avg_sal > 1000ORDERBY avg_sal DESCLIMIT 0,2

1.23.4 数据分组的总结

SELECT column1 , column2 . column3. . FROM  tablegroup by columnhaving conditionorder by columnlimit start, rows ;

1.24 mysql 多表查询

1.24.1 说明

        多表查询是指基于两个和两个以上的表查询.在实际应用中,查询单个表可能不能满足你的需求,需要使用到(dept表和emp表)

1.24.2 多表查询练习

--多表查询
--?显示雇员名,雇员工资及所在部门的名字【笛卡尔集】
/*分析1.雇员名,雇员工资来自emp表2. 部门的名字 来自 dept表3. 需求对 emp 和 dept查询 ename,sal,dname,deptno4. 当我们需要指定显示某个表的列是,需要 表.列表
*/SELECT ename,sal,dname,emp.deptnoFROM emp,deptWHERE emp.deptno = dept.deptnoSELECT * FROM emp;SELECT * FROM dept;SELECT * FROM salgrade;
-- 小技巧:多表查询的条件不能少于 表的个数-1, 否则会出现笛卡尔集
-- ?如何显示部门号为10的部门名、员工名和工SELECT ename,sal,dname, emp.deptnoFROM emp, deptWHERE emp.deptno = dept.deptno AND emp.deptno = 10-- ?显示各个员工的姓名,工资,及其工资的级别-- 思路 姓名,工资 来自 emp13
-- 工资级别 salgrade5
-- 写sql , 先写一个简单,然后加入过滤条件...select ename, sal, gradefrom emp , salgradewhere sal between losal and hisal;

1.24.3 自连接

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

--多表查询的自连接--思考题:显示公司员工名字和他的上级的名字--分析:员工名字在emp,上级的名字的名字emp
--员工和上级是通过emp表的mgr列关联
--小结:
--自连接的特点1.把同一张表当做两张表使用
--   2.需要给表取别名表名表别名
-- 3.列名不明确,可以指定列的别名列名as列的别名SELECT worker.ename AS '职员名' , boss.enameAS'上级名'FROM emp worker,emp bossWHERE worker.mgr = boss.empno;SELECT * FROM emp;

1.25 mysql表子查询

1.25.1 什么是子查询

子查询是指嵌入在其它sql语句中的select语句,也叫嵌套查询

1.25.2 单行子查询

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

1.25.3 多行子查询

--子查询的演示
--请思考:如何显示与SMITH同一部门的所有员工?/*1.先查询到SMITH的部门号得到2.把上面的select语句当做一个子查询来使用
*/SELECT deptnoFROM empWHERE ename ='SMITH'--下面的答案.SELECT *FROM empWHERE deptno =(SELECT deptnoFROM empWHERE ename ='SMITH')
--课堂练习:如何查询和部门10的工作相同的雇员的
--名字、岗位、工资、部门号,但是不含10号部门自己的雇员./*1.查询到10号部门有哪些工作2.把上面查询的结果当做子查询使用
*/select distinct jobfrom empwhere deptno =10;--下面语句完整select ename,job,sal,deptnofrom empwhere job in(SELECT DISTINCT jobFROM empWHERE deptno = 10) and deptno <> 10

1.25.4 在多行子查询中使用all操作符

--all和any的使用--请思考:显示工资比部门30的所有员工的工资高的员工的姓名、工资和部门号SELECT ename,sal,deptnoFROM empWHERE sal > ALL(SELECT salFROM empWHERE deptno = 30)-- 可以这样写SELECT ename, sal, deptnoFROM empWHERE sal > (SELECT MAX(sal)FROM empWHERE deptno = 30)-- 请思考:如何显示工资比部门30的其中一个员工的工资高的员工的姓名、工资和部门号SELECT ename, sal, deptnoFROM empWHERE sal > any(SELECT salFROM empWHERE deptno = 30)SELECT ename, sal, deptnoFROM empWHERE sal > (SELECT min(sal)FROM empWHERE deptno = 30)-- 查询ecshop 中各个类别中,价格最高的商品-- 查询 商品表
-- 先得到 各个类别中,价格最高的商品 max + groupbycat_id, 当做临时表
-- 把子查询当做一张临时表可以解决很多很多复杂的查询select cat_id , max(shop_price)from ecs_goodsgroup by cat_id-- 这个最后答案select goods_id, ecs_goods.cat_id, goods_name, shop_pricefrom (SELECT cat_id , MAX(shop_price) as max_priceFROM ecs_goodsGROUP BY cat_id) temp , ecs_goodswhere temp.cat_id = ecs_goods.cat_idand temp.max_price = ecs_goods.shop_price

1.25.5 多列子查询

--多列子查询--请思考如何查询与allen的部门和岗位完全相同的所有雇员(并且不含allen本人)
--(字段1,字段2...)=(select字段1,字段2from。。。。)--分析:1.得到smith的部门和岗位SELECT deptno,jobFROM empWHERE ename = 'ALLEN'-- 分析:2 把上面的查询当做子查询来使用,并且使用多列子查询的语法进行匹配SELECT *FROM empWHERE(deptno , job) = (SELECT deptno , jobFROM empWHERE ename ='ALLEN') AND ename != 'ALLEN-- 请查询 和宋江数学,英语,语文
-- 成绩 完全相同的学生SELECT *FROM studentWHERE(math, english, chinese) = (SELECT math, english, chineseFROM studentWHERE`name` = '宋江')SELECT * FROM student;

1.25.6 在from子句中使用子查询

--子查询练习--请思考:查找每个部门工资高于本部门平均工资的人的资料
--这里要用到数据查询的小技巧,把一个子查询当作一个临时表使用--1.先得到每个部门的部门号和对应的平均工资SELECT deptno,AVG(sal) AS avg_salFROM emp GROUP BY deptno--2.把上面的结果当做子查询,和emp进行多表查询SELECT ename,sal,temp.avg_sal,emp.deptnoFROM emp,(SELECT deptno,AVG(sal) AS avg_salFROM empGROUP BY deptno) tempWHERE emp.deptno = temp.deptnoAND emp.sal > temp.avg_sal-- 查找每个部门工资最高的人的详细资料SELECT ename, sal, temp.max_sal, emp.deptnoFROM emp,(SELECT deptno, MAX(sal)AS max_salFROM empGROUP BY deptno) tempWHERE emp.deptno = temp.deptno AND emp.sal = temp.max_sal-- 查询每个部门的信息(包括:部门名,编号,地址)和人员数量,我们一起完成。- 1. 部门名,编号,地址 来自 dept表
-- 2. 各个部门的人员数量-》 构建一个临时表SELECT COUNT(*), deptnoFROM empGROUP BY deptno;SELECT dname,dept.deptno,loc,tmp.per_numAS'人数'FROM dept,(SELECT COUNT(*) AS per_num,deptnoFROM empGROUP BY deptno)tmpWHERE tmp.deptno = dept.deptno--还有一种写法表.*表示将该表所有列都显示出来,可以简化sql语句
--在多表查询中,当多个表的列不重复时,才可以直接写列名SELECT tmp.*, dname,locFROM dept,(SELECT COUNT(*) ASper_num,deptnoFROM empGROUP BY deptno) tmpWHERE tmp.deptno = dept.deptno

1.26 表复制

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

-- 表的复制
-- 为了对某个sql语句进行效率测试,我们需要海量数据时,可以使用此法为表创建海量数据CREATE TABLE my_tab01( id INT,`name` VARCHAR(32),sal DOUBLE,job VARCHAR(32),deptno INT);DESC my_tab01SELECT * FROM my_tab01;-- 演示如何自我复制
-- 1. 先把emp 表的记录复制到 my_tab01INSERT INTO my_tab01(id, `name`, sal, job,deptno)SELECT empno, ename, sal, job, deptno FROM emp;-- 2. 自我复制INSERT INTO my_tab01SELECT * FROM my_tab01;SELECT COUNT(*) FROM my_tab01;-- 如何删除掉一张表重复记录
-- 1. 先创建一张表 my_tab02,
-- 2. 让 my_tab02 有重复的记CREATE TABLE my_tab02 LIKE emp;  -- 这个语句 把emp表的结构(列),复制到my_tab02DESCmy_tab02;INSERT INTO my_tab02SELECT * FROM emp;SELECT * FROM my_tab02;-- 3. 考虑去重 my_tab02的记录
/*思路(1) 先创建一张临时表 my_tmp, 该表的结构和 my_tab02一样(2) 把my_tmp 的记录 通过 distinct 关键字 处理后 把记录复制到 my_tmp(3) 清除掉 my_tab02 记录(4) 把 my_tmp 表的记录复制到 my_tab02(5) drop 掉 临时表my_tmp*/
-- (1) 先创建一张临时表 my_tmp, 该表的结构和 my_tab02一样create table my_tmp like my_tab02
-- (2) 把 my_tmp 的记录 通过 distinct 关键字 处理后 把记录复制到 my_tmpinsert into my_tmpselect distinct * from my_tab02;
-- (3) 清除掉 my_tab02 记录delete from my_tab02;
-- (4) 把 my_tmp 表的记录复制到 my_tab02insert into my_tab02select * from my_tmp;
-- (5) drop 掉 临时表my_tmpdrop table my_tmp;select * from my_tab02;

1.27 合并查询

1.27.1 介绍

-- 合并查询SELECT ename,sal,job FROM emp WHERE sal>2500  -- 5SELECT ename,sal,job FROM emp WHERE job='MANAGER'  -- 3-- union all 就是将两个查询结果合并,不会去重SELECT ename,sal,job FROM emp WHERE sal>2500  -- 5UNION ALLSELECT ename,sal,job FROM emp WHERE job='MANAGER' -- 3-- union 就是将两个查询结果合并,会去重SELECT ename,sal,job FROM emp WHERE sal>2500  -- 5UNIONSELECT ename,sal,job FROM emp WHERE job='MANAGER'  -- 3

1.28 mysql 表外连接

1.28.1 外连接

1. 左外连接(如果左侧的表完全显示我们就说是左外连接)
2. 右外连接(如果右侧的表完全显示我们就说是右外连接)。

-- 外连接--比如:列出部门名称和这些部门的员工名称和工作,
--同时要求显示出那些没有员工的部门--使用我们学习过的多表查询的SQL,看看效果如何?SELECT dname,ename,jobFROM emp,deptWHERE emp.deptno = dept.deptnoORDER BY dnameSELECT * FROM dept;SELECT * FROM emp;-- 创建 stu/*id name1 Jack2 Tom3 Kity4 nono*/CREATE TABLE stu(id INT,`name` VARCHAR(32));INSERT INTO stu VALUES(1, 'jack'),(2,'tom'),(3, 'kity'),(4, 'nono');SELECT * FROM stu;
-- 创建 exam
/*id  grade1   562   7611   8
*/CREATE TABLE exam(id INT,grade INT);INSERT INTO exam VALUES(1, 56),(2,76),(11, 8);SELECT * FROM exam;-- 使用左连接
-- (显示所有人的成绩,如果没有成绩,也要显示该人的姓名和id号,成绩显示为空)SELECT `name`, stu.id, gradeFROM stu, examWHERE stu.id = exam.id;-- 改成左外连接
SELECT`name`, stu.id, gradeFROM stu LEFTJOIN examON stu.id = exam.id;-- 使用右外连接(显示所有成绩,如果没有名字匹配,显示空)
-- 即:右边的表(exam) 和左表没有匹配的记录,也会把右表的记录显示出来
SELECT`name`, stu.id, gradeFROM stu RIGHT JOIN examON stu.id = exam.id;-- 列出部门名称和这些部门的员工信息(名字和工作),
-- 同时列出那些没有员工的部门名。5min
-- 使用左外连接实现
SELECT dname, ename, jobFROM dept LEFTJOIN empON dept.deptno = emp.deptno-- 使用右外连接实现
SELECT dname, ename, jobFROM emp RIGHT JOIN deptON dept.deptno = emp.deptno

1.29 mysql 约束

1.29.1 基本介绍

        约束用于确保数据库的数据满足特定的商业规则。在mysql中,约束包括: not null、unique,primary key,foreign key,和check五种.

1.29.2 primarykey(主键)-基本使用

        字段名  字段类型  primary key
用于唯一的标示表行的数据,当定义主键约束后,该列不能重复

--主键使用--id name emailCREATE TABLE t17(id INT PRIMARY KEY,  --表示id列是主键`name` VARCHAR(32),email VARCHAR(32));-- 主键列的值是不可以重复INSERT INTO t17VALUES(1, 'jack', 'jack@sohu.com');INSERT INTO t17VALUES(2, 'tom', 'tom@sohu.com');INSER TINTO t17VALUES(1, 'hsp', 'zak@sohu.com');SELECT * FROM t17-- 主键使用的细节讨论
-- primary key 不能重复而且不能为 null。
INSERT INTO t17VALUES(NULL, 'zak', 'zak@sohu.com');
-- 一张表最多只能有一个主键, 但可以是复合主键(比如 id+name)CREATE TABLE t18(id INT PRIMARYKEY, -- 表示id列是主键`name` VARCHAR(32), PRIMARYKEY  -- 错误的email VARCHAR(32));
-- 演示复合主键 (id 和 name 做成复合主键)CREATE TABLE t18(id INT ,`name` VARCHAR(32),email VARCHAR(32),PRIMARY KEY(id, `name`) -- 这里就是复合主键);INSERT INTO t18VALUES(1, 'tom', 'tom@sohu.com');INSERT INTO t18VALUES(1, 'jack', 'jack@sohu.com');INSERT INTO t18VALUES(1, 'tom', 'xx@sohu.com'); -- 这里就违反了复合主键
SELECT * FROM t18;-- 主键的指定方式 有两种
-- 1. 直接在字段名后指定:字段名 primakry key
-- 2. 在表定义最后写 primary key(列名)
CREATE TABLE t19(id INT ,`name` VARCHAR(32) PRIMARY KEY,email VARCHAR(32));CREATE TABLE t20(id INT ,`name` VARCHAR(32) ,email VARCHAR(32),PRIMARY KEY(`name`)  -- 在表定义最后写 primary key(列名);--使用desc表名,可以看到primarykey的情况DESC t20 --查看t20表的结果,显示约束的情况
DESC t18

1.29.3 not null(非空)

如果在列上定义了not null,那么当插入数据时,必须为列提供数据。
        字段名  字段类型 not null

1.29.4 unique(唯一)

当定义了唯一约束后,该列值是不能重复的.。
         字段名  字段类型  unique
unique细节(注意): 
1. 如果没有指定not null,则unique字段可以有多个null        2. 一张表可以有多个unique字段

--unique的使用CREATE TABLE t21(id INT UNIQUE, --表示id列是不可以重复的.`name` VARCHAR(32),email VARCHAR(32));INSERT INTO t21VALUES(1, 'jack', 'jack@sohu.com');INSERT INTO t21VALUES(1, 'tom', 'tom@sohu.com');--unqiue使用细节
--1.如果没有指定notnull,则unique字段可以有多个null
--如果一个列(字段),是unique not null使用效果类似primary keyINSERT INTO t21VALUES (NULL, 'tom', 'tom@sohu.com');SELECT * FROM t21;
--2. 一张表可以有多个unique字段
CREATE TABLE t22(id INT UNIQUE, --表示id列是不可以重复的.`name` VARCHAR(32) UNIQUE, --表示name不可以重复email VARCHAR(32));DESC t22

1.29.5 foreignkey(外键)

        用于定义主表和从表之间的关系:外键约束要定义在从表上,主表则必须具有主键约束或是unique约束.  当定义外键约束后,要求外键列数据必须在主表的主键列存在或是为null(学生/班级图示)

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

-- 外键演示-- 创建 主表 my_classCREATE TABLE my_class (id INT PRIMARYKEY,  -- 班级编号`name` VARCHAR(32) NOT NULL DEFAULT ');-- 创建 从表 my_stuCREATE TABLE my_stu (id INT PRIMARY KEY, -- 学生编号`name` VARCHAR(32) NOTNULLDEFAULT ',class_id INT ,-- 学生所在班级的编号
-- 下面指定外键关系FOREIGN KEY(class_id) REFERENCES my_class(id)) 
-- 测试数据
INSERT INTO my_classVALUES(100, 'java'), (200, 'web');
INSERT INTO my_classVALUES(300, 'php');SELECT * FROM my_class;
INSERT INTO my_stuVALUES(1, 'tom', 100);
INSERT INTO my_stuVALUES(2, 'jack', 200);
INSERT INTO my_stuVALUES(3, 'zak', 300);
INSERT INTO my_stuVALUES(4, 'mary', 400); -- 这里会失败...因为 400 班级不存在INSERT INTO my_stuVALUES(5, 'king', NULL);  -- 可以, 外键 没有写 not null
SELECT * FROM my_class;-- 一旦建立主外键的关系,数据不能随意删除了
DELETE FROM my_classWHERE id = 100;

1.29.6 check

        用于强制行数据必须满足的条件,假定在sal列上定义了check约束,并要求sal列值在1000 ~2000之间如果不再1000~2000之间就会提示出错。
提示: oracle和sql server均支持check ,但是mysql5.7目前还不支持check ,只做语法校验,但不会生效。

        在mysql中实现 check 的功能,一般是在程序中控制,或者通过触发器完成。

-- 演示check的使用
-- mysql5.7 目前还不支持check ,只做语法校验,但不会生效
-- 了解
-- 学习 oracle, sql server, 这两个数据库是真的生效-- 测试
CREATE TABLE t23 (id INT PRIMARY KEY,`name` VARCHAR(32) ,sex VARCHAR(6) CHECK (sex IN('man','woman')),sal DOUBLE CHECK( sal> 1000AND sal <2000));-- 添加数据
INSERT INTO t23VALUES(1, 'jack', 'mid', 1);SELECT * FROM t23;

1.29.7 商店售货系统表设计案例

-- 使用约束的练习CREATE DATABASE shop_db-- 现有一个商店的数据库shop_db,记录客户及其购物情况,由下面三个表组成:
-- 商品goods(商品号goods_id,商品名goods_name,单价unitprice,商品类别category,
-- 供应商provider);
-- 客户customer(客户号customer_id,姓名 name,住址address,电邮 email 性别 sex,身份证card_Id);
-- 购买purchase(购买订单号order_id,客户号customer_id,商品号goods_id,购买数量nums);
-- 1 建表,在定义中要求声明 [进行合理设计]:
-- (1)每个表的主外键;
-- (2)客户的姓名不能为空值;
-- (3)电邮不能够重复;
-- (4)客户的性别[男|女]check 枚举..
-- (5)单价 unitprice 在 1.0- 9999.99 之间 check-- 商品goodsCREATE TABLE goods (goods_id INT PRIMARY KEY,goods_name VARCHAR(64) NOT NULL DEFAULT ",unitprice DECIMAL(10,2) NOT NULL DEFAULT 0CHECK(unitprice >= 1.0AND unitprice <= 9999.99),category INT NOT NULL DEFAULT 0,provider VARCHAR(64) NOT NULL DEFAULT ");-- 客户customer(客户号customer_id,姓名 name,住址address,电邮 email 性别 sex,
--身份证card_Id);CREATE TABLE customer(customer_id CHAR(8) PRIMARY KEY, --程序员自己决定`name` VARCHAR(64) NOT NULL DEFAULT ",address VARCHAR(64) NOT NULL DEFAULT ",email VARCHAR(64) UNIQUE NOT NULL,sex ENUM('男','女') NOT NULL, --这里使用的枚举类型,card_Id CHAR(18));--购买purchase(购买订单号order_id,客户号customer_id,商品号goods_id,
--购买数量nums);
CREATE TABLE purchase(order_id INT UNSIGNED PRIMARY KEY,customer_id CHAR(8) NOT NULL DEFAULT ", --外键约束在后goods_id INT NOT NULL DEFAULT 0, --外键约束在后nums INT NOT NULL DEFAULT 0,FOREIGN KEY(customer_id) REFERENCES customer (customer_id),FOREIGN KEY (goods_id) REFERENCES goods(goods_id));DESC goods; DESC customer;DESC purchase;

1.30 自增长

        在某张表中,存在一个id列(整数),我们希望在添加记录的时候,该列从1开始,自动的增长,怎么处理?                 字段名  整型  primary  key auto_increment

1.30.1 自增长使用细节

1. 一般来说自增长是和primary key配合使用的
2. 自增长也可以单独使用[但是需要配合一个unique]
3. 自增长修饰的字段为整数型的(虽然小数也可以但是非常非常少这样使用)
4. 自增长默认从1开始,你也可以通过如下命令修改alter  table表名auto_increment = 新的开始值;
5. 如果你添加数据时,给自增长字段(列)指定的有值,则以指定的值为准,如果指定了自增长,一般来说,就按照自增长的规则来添加数据。

--演示自增长的使用--创建表
CREATE TABLE t24(id INT PRIMARY KEY AUTO_INCREMENT,email VARCHAR(32) NOT NULL DEFAULT ",`name` VARCHAR(32) NOT NULL DEFAULT ");DESC t24
--测试自增长的使用
INSERT INTO t24VALUES(NULL, 'tom@qq.com', 'tom');INSERT INTO t24(email, `name`) VALUES ('zak@sohu.com', 'zak');SELECT * FROM t24;-- 修改默认的自增长开始值
ALTER TABLE t25 AUTO_INCREMENT = 100
CREATE TABLE t25(id INT PRIMARY KEY AUTO_INCREMENT,email VARCHAR(32) NOT NULLDEFAULT ",`name` VARCHAR(32) NOT NULL DEFAULT ");
INSERT INTO t25VALUES(NULL, 'mary@qq.com', 'mary');
INSERT INTO t25VALUES(666, 'zak@qq.com', 'zak');
SELECT * FROM t25;CREATE DATABASE tmp;CREATE TABLE dept( /*部门表*/deptno MEDIUMINT UNSIGNED NOTNULL DEFAULT0,dname VARCHAR(20) NOTNULL DEFAULT "",loc VARCHAR(13) NOT NULL DEFAULT "") ;#创建表EMP雇员
CREATE TABLE emp(empno MEDIUMINT UNSIGNED NOTNULL DEFAULT0, /*编号*/ename VARCHAR(20) NOT NULL DEFAULT "",  /*名字*/job VARCHAR(9) NOT NULL DEFAULT "", /*工作*/mgr MEDIUMINT UNSIGNED NOT NULL DEFAULT 0, /*上级编号*/hiredate DATE NOT NULL,/*入职时间*/sal DECIMAL(7,2) NOT NULL, /*薪水*/comm DECIMAL(7,2) NOT NULL,/*红利*/deptno MEDIUMINT UNSIGNED NOT NULL DEFAULT 0 /*部门编号*/) ;#工资级别表
CREATE TABLE salgrade(grade MEDIUMINT UNSIGNED NOT NULL DEFAULT 0,losal DECIMAL(17,2) NOT NULL,hisal DECIMAL(17,2) NOT NULL);#测试数据INSERT INTO salgrade VALUES (1,700,1200);INSERT INTO salgrade VALUES (2,1201,1400);INSERT INTO salgrade VALUES (3,1401,2000);INSERT INTO salgrade VALUES (4,2001,3000);INSERT INTO salgrade VALUES (5,3001,9999);

1.31 mysql索引

1.31.1 索引快速入门

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

        是不是建立一个索引就能解决所有的问题?
        ename上没有建立索引会怎样?
        select * from emp where ename = 'axJxC' ;

--创建测试数据库 tmpCREATE DATABASE tmp;CREATE TABLE dept( /*部门表*/deptno MEDIUMINT UNSIGNED NOTNULL DEFAULT 0,dname VARCHAR(20) NOT NULL DEFAULT "",loc VARCHAR(13) NOT NULL DEFAULT "");#创建表EMP雇员
CREATE TABLE emp(empno MEDIUMINT UNSIGNED NOTNULL DEFAULT0,/*编号*/ename VARCHAR(20) NOT NULL DEFAULT "",/*名字*/job VARCHAR(9) NOT NULL DEFAULT "",/*工作*/mgr MEDIUMINT UNSIGNED NOT NULL DEFAULT 0,/*上级编号*/hiredate DATE NOT NULL,/*入职时间*/sal DECIMAL(7,2) NOT NULL,/*薪水*/comm DECIMAL(7,2) NOT NULL,/*红利*/deptno MEDIUMINT UNSIGNED NOT NULL DEFAULT 0/*部门编号*/) ;#工资级别表
CREATE TABLE salgrade(grade MEDIUMINT UNSIGNED NOT NULL DEFAULT 0,losal DECIMAL(17,2) NOT NULL,hisal DECIMAL(17,2) NOT NULL);#测试数据INSERT INTO salgrade VALUES (1,700,1200);INSERT INTO salgrade VALUES (2,1201,1400);INSERT INTO salgrade VALUES (3,1401,2000);INSERT INTO salgrade VALUES (4,2001,3000);INSERT INTO salgrade VALUES (5,3001,9999);DELIMITER $$#创建一个函数,名字 rand_string,可以随机返回我指定的个数字符串
CREATE FUNCTION rand_string(n INT)
RETURNS VARCHAR(255)  #该函数会返回一个字符串
BEGIN#定义了一个变量 chars_str, 类型 varchar(100)#默认给 chars_str 初始值 'abcdefghijklmnopqrstuvwxyzABCDEFJHIJKLMNOPQRSTUVWXYZ'DECLARE chars_str VARCHAR(100) DEFAULT'abcdefghijklmnopqrstuvwxyzABCDEFJHIJKLMNOPQRSTUVWXYZ';DECLARE return_str VARCHAR(255) DEFAULT ";DECLARE i INT DEFAULT 0;WHILE i <nDO# concat 函数 : 连接函数mysql函数SET return_str = CONCAT(return_str,SUBSTRING(chars_str,FLOOR(1+RAND()*52),1));SET i =i +1;END WHILE;RETURN return_str;END $$#这里我们又自定了一个函数,返回一个随机的部门号
CREATE FUNCTION rand_num( )RETURNS INT(5)BEGINDECLARE i INT DEFAULT 0;SET i = FLOOR(10+RAND()*500);RETURN i;END $$#创建一个存储过程, 可以添加雇员
CREATE PROCEDURE insert_emp(IN STARTINT(10),IN max_num INT(10))BEGINDECLARE i INT DEFAULT 0;#set autocommit =0 把 autocommit 设置成 0#autocommit = 0 含义: 不要自动提交
SET autocommit = 0; #默认不提交sql 语句
REPEATSET i =i +1;#通过前面写的函数随机产生字符串和部门编号,然后加入到emp表
INSERT INTO emp VALUES ((START+i) ,rand_string(6),'SALESMAN',0001,CURDATE(),2000,400,rand_num());UNTIL i = max_numEND REPEAT;#commit 整体提交所有sql语句,提高效率
COMMIT;END $$#添加8000000 数据
CALL insert_emp(100001,8000000)$$#命令结束符,再重新设置为;DELIMITER ;SELECT COUNT(*) FROM emp;-- 在没有创建索引时,我们的查询一条记录SELECT *FROM empWHERE empno = 1234567
-- 使用索引来优化一下, 体验索引的牛-- 在没有创建索引前 ,emp.ibd 文件大小 是 524m
-- 创建索引后 emp.ibd 文件大小 是 655m[索引本身也会占用空间.]
-- 创建ename列索引,emp.ibd 文件大小 是 827m-- empno_index 索引名称
-- ON emp (empno) : 表示在 emp表的 empno列创建索引
CREATE INDEX empno_index ON emp (empno)-- 创建索引后, 查询的速度如何SELECT *FROM empWHERE empno = 1234578  -- 0.003s 原来是4.5s-- 创建索引后,只对创建了索引的列有效
SELECT *FROM empWHERE ename ='PjDlwy' -- 没有在ename创建索引时,时间4.7sCREATE INDEX ename_index ON emp (ename)  -- 在 ename 上创建索引

1.31.2 索引的类型

1. 主键索引,主键自动的为主索引(类型Primary key)
2. 唯一索引(UNIQUE)
3. 普通索引(INDEX)
4. 全文索引(FULLTEXT)[适用于MyISAM] 一般开发,不使用mysql自带的全文索引,而是使用:全文搜索Solr和 ElasticSearch (ES)

create table t1 (
id int primary key,--主键,同时也是索引,称为主键索引.name varchar(32));
create table t2(
id int unique, -- id是唯一的,同时也是索引,称为unique索引.

1.31.3 索引使用

--演示mysql的索引的使用--创建索引
CREATE TABLE t25(id INT,`name` VARCHAR(32));--查询表是否有索引
SHOW INDEXES FROM t25;--添加索引
--添加唯一索引
CREATE UNIQUE INDEXid_index ON t25(id);--添加普通索引方式1CREATE INDEX id_index ON t25(id);
--如何选择
-- 1. 如果某列的值,是不会重复的,则优先考虑使用unique索引, 否则使用普通索引
-- 添加普通索引方式2ALTER TABLE t25 ADD INDEXid_index (id)-- 添加主键索引
CREATE TABLE t26 (id INT ,`name` VARCHAR(32));ALTER TABLE t26 ADD PRIMARY KEY(id)SHOW INDEX FROM t25-- 删除索引
DROP INDEX id_index ON t25  
-- 删除主键索引
ALTER TABLE t26 DROP PRIMARY KEY-- 修改索引 , 先删除,在添加新的索引-- 查询索引
-- 1. 方式
SHOW INDEX FROM t25
-- 2. 方式
SHOW INDEXES FROM t25
-- 3. 方式
SHOW KEYS FROM t25
-- 4 方式
DESC t25

1.31.4  小结: 哪些列上适合使用索引

1.32 mysql 事务

1.32.1 什么是事务

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

1.32.2 事务和锁

        当执行事务操作时(dml语句) ,mysql会在表上加锁,防止其它用户改表的数据.这对用户来讲是非常重要的

--事务的一个重要的概念和具体操作
--看一个图[看示意图]
--演示
--1.创建一张测试表
CREATE TABLE t27(id INT,`name` VARCHAR(32));--2.开始事务
START TRANSACTION--3.设置保存点
SAVEPOINT a
--执行dml操作
INSERT INTO t27 VALUES(100, 'tom');SELECT * FROM t27;SAVEPOINT b
--执行dml操作
INSERT INTO t27 VALUES(200, 'jack');-- 回退到 bROLLBACK TO b
-- 继续回退 aROLLBACK TO a
-- 如果这样, 表示直接回退到事务开始的状态.ROLLBACKCOMMIT

1.32.3 回退事务

        在介绍回退事务前,先介绍一下保存点(savepoint).保存点是事务中的点.用于取消部分事务,当结束事务时(commit),会自动的删除该事务所定义的所有保存点当执行回退事务时,通过指定保存点可以回退到指定的点,

1.32.4 提交事务

        使用commit语句可以提交事务.当执行了commit语句子后,会确认事务的变化、结束事务、删除保存点、释放锁,数据生效。当使用commit语句结束事务子后,其它会话[其他连接]将可以查看到事务变化后的新数据 [所有数据就正式生效.]

1.32.5 事务细节讨论

1. 如果不开始事务,默认情况下,dml操作是自动提交的,不能回滚
2. 如果开始一个事务,你没有创建保存点.你可以执行 rollback,默认就是回退到你事务开始的状态.
3. 你也可以在这个事务中(还没有提交时),创建多个保存点.比如: savepoint aaa;执行dml , savepoint bbb;
4. 你可以在事务没有提交前,选择回退到哪个保存点.
5. mysql的事务机制需要innodb的存储引擎才可以使用,myisam不好使.
6. 开始一个事务start  transaction,  set  autocommit = off;

-- 讨论 事务细节--1.如果不开始事务,默认情况下,dml操作是自动提交的,不能回滚
INSERT INTO t27 VALUES(300, 'milan');  --自动提交commitSELECT * FROM t27--2.如果开始一个事务,你没有创建保存点.你可以执行rollback,
--默认就是回退到你事务开始的状态START TRANSACTIONINSERT INTO t27 VALUES (400, 'king');INSERT INTO t27 VALUES(500, 'scott');ROLLBACK  --表示直接回退到事务开始的的状态COMMIT;--3.你也可以在这个事务中(还没有提交时),创建多个保存点.比如:savepoint aaa;
-- 执行dml,savepoint bbb--4. 你可以在事务没有提交前,选择回退到哪个保存点
--5. InnoDB 存储引擎支持事务, MyISAM 不支持
--6. 开始一个事务start transaction, set autocommit = off;

1.33 mysql事务隔离级别

1.33.1 事务隔离级别介绍

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

1.33.2 查看事务隔离级别

脏读(dirty read): 当一个事务读取另一个事务尚未提交的改变(update,insert,delete)时,产生脏读
不可重复读(nonrepeatable read): 同一查询在同一事务中多次进行,由于其他提交事务所做的修改或删除,每次返回不同的结果集,此时发生不可重复读。
幻读(phantom read): 同一查询在同一事务中多次进行,由于其他提交事务所做的插入操作,每次返回不同的结果集,此时发生幻读。

1.33.3 事务隔离级别

1.33.4 设置事务隔离级别

1. 查看当前会话隔离级别        select @ @ tx isolation;
2. 查看系统当前隔离级别        select @ @global.tx_isolation;
3. 设置当前会话隔离级别
set session transaction isolation level repeatable read;
4. 设置系统当前隔离级别
set global transaction isolation level repeatable read;
5. mysql 默认的事务隔离级别是repeatable read,一般情况下,没有特殊要求,没有必要修改(因为该级别可以满足绝大部分项目需求)

-- 演示mysql 的事务隔离级别-- 1. 开了两个mysql的控制台
-- 2. 查看当前mysql的隔离级别
SELECT @@tx_isolation;-- mysql> SELECT @@tx_isolation;
-- +-----------------+
-- | @@tx_isolation |
-- +-----------------+
-- | REPEATABLE-READ |
-- +------------------- 3.把其中一个控制台的隔离级别设置 Read uncommitted
SET SESSION TRANSACTION ISOLATION LEVELREAD UNCOMMITTED-- 4. 创建表
CREATE TABLE `account`(id INT,`name` VARCHAR(32),money INT);-- 查看当前会话隔离级别
SELECT @@tx_isolation
-- 查看系统当前隔离级别
SELECT @@ global.tx_isolation
-- 设置当前会话隔离级别
SET SESSION TRANSACTION ISOLATION LEVELREADUNCOMMITTED
-- 设置系统当前隔离级别
SET GLOBAL TRANSACTION ISOLATION LEVEL[你设置的级别]

1.34 mysql 事务 ACID

1.34.1 事务的acid 特性

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

1.35 mysql 表类型和存储引擎

1.35.1 基本介绍

1. MySQL的表类型由存储引擎(Storage Engines)决定,主要包括MylSAM 、innoDB、Memory等。
2. MySQL 数据表主要支持六种类型,分别是:CSV、Memory、ARCHIVE、MRG_MYISAM、MYISAM、InnoBDB。
3. 这六种又分为两类,一类是”事务安全型”(transaction-safe),比如: InnoDB; 其余都属于第二类,称为”非事务安全型”(non-transaction-safe)[mysiam和memory].

1.35.2 主要的存储引擎/表类型特点

1.35.3 细节说明

1. MylSAM不支持事务、也不支持外键,但其访问速度快,对事务完整性没有要求
2. InnoDB存储引擎提供了具有提交、回滚和崩溃恢复能力的事务安全。但是比起 MylSAM存储引擎,InnoDB写的处理效率差一些并且会占用更多的磁盘空间以保留数据和索引。
3. MEMORY存储引擎使用存在内存中的内容来创建表。每个MEMORY表只实际对应
个磁盘文件。MEMORY类型的表访问非常得快,因为它的数据是放在内存中的,并且默认使用HASH索引。但是一旦MySQL服务关闭,表中的数据就会丢失掉,表的结构还在。

1.35.4 三种存储引擎表使用案例

--表类型和存储引擎--查看所有的存储引擎
SHOW ENGINES
--innodb存储引擎,是前面使用过.
--1.支持事务    2.支持外键    3.支持行级锁--myisam存储引擎
CREATE TABLE t28(id INT,`name` VARCHAR(32)) ENGINE MYISAM
-- 1.添加速度快    2.不支持外键和事务    3.支持表级锁START TRANSACTION;SAVEPOINT t1INSERT 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 MEMORYDESC t29INSERTINTO t29VALUES(1,'tom'), (2,'jack'), (3, 'zak');SELECT * FROM t29-- 指令修改存储引擎
ALTER TABLE `t29` ENGINE = INNODB

1.35.5 如何选择表的存储引擎

1. 如果你的应用不需要事务,处理的只是基本的CRUD操作,那么MylSAM 是不二选择,速度快
2. 如果需要支持事务,选择lnnoDB。
3. Memory存储引擎就是将数据存储在内存中,由于没有磁盘I./O的等待,速度极快。但由于是内存存储引擎,所做的任何修改在服务器重启后都将消失。(经典用法: 用户的在线状态().)

1.35.6 修改存储引擎

        ALTER TABLE  '表名'  ENGINE = 储存引擎;

1.36 视图(view)

1.36.1 基本概念

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

1.36.2 视图的基本使用

1. create view视图名as select语句
2. alter view视图名as select语句 --更新成新的视图
3. SHoW CREATE VIEW 视图名
4. drop view视图名1,视图名2

--视图的使用
--创建一个视图emp_view01,只能查询emp表的(empno、ename,job和deptno)信息--创建视图
CREATE VIEW emp_view01ASSELECTempno, ename, job, deptno FROM emp;-- 查看视图
DESC emp_view01SELECT * FROM emp_view01;SELECT empno, job FROM emp_view01;-- 查看创建视图的指令SHOW CREATE VIEW emp_view01
-- 删除视图DROP VIEW emp_view01;-- 视图的细节-- 1. 创建视图后,到数据库去看,对应视图只有一个视图结构文件(形式: 视图名.frm)
-- 2. 视图的数据变化会影响到基表,基表的数据变化也会影响到视图[insert update delete]-- 修改视图 会影响到基表UPDATE emp_view01SET job = 'MANAGER'WHERE empno = 7369SELECT * FROM emp; -- 查询基表SELECT  *FROM emp_view01
--修改基本表,会影响到视图UPDATE empSET job ='SALESMAN'WHERE empno = 7369--3.视图中可以再使用视图,比如从emp_view01视图中,选出empno,和ename做出新视图
DESC emp_view01CREATE VIEW emp_view02ASSELECT empno,ename FROM emp_view01SELECT * FROM emp_view02

1.36.3 视图细节讨论

1. 创建视图后,到数据库去看,对应视图只有一个视图结构文件(形式:视图名.frm)
2. 视图的数据变化会影响到基表,基表的数据变化也会影响到视图[insert update delete ]
---准针对前面的雇员管理系统-----
mysql> create view myview as select empno ,ename , job, comm from emp;
mysql> select * from myview;
mysql> update myview set comm=200 where empno=7369;//修改视图,对基表都有变化
mysql> update emp set comm=100 where empno=7369;//修改基表,对视频也有变化
3. 视图中可以再使用视图,数据仍然来自基表..

1.36.4 视图最佳实践

1. 安全。一些数据表有着重要的信息。有些字段是保密的,不能让用户直接看到。这时就可以创建一个视图,在这张视图中只保留一部分字段。这样,用户就可以查询自己需要的字段,不能查看保密的字段。
2. 性能。关系数据库的数据常常会分表存储,使用外键建立这些表的之间关系。这时,数据库查询通常会用到连接(JOIN)。这样做不但麻烦,效率相对也比较低。如果建立一个视图,将相关的表和字段组合在一起,就可以避免使用JOIN查询数据。
3. 灵活。如果系统中有一张旧的表,这张表由于设计的问题,即将被废弃。然而,很多应用都是基于这张表,不易修改。这时就可以建立一张视图,视图中的数据直接映射到新建的表。这样,就可以少做很多改动,也达到了升级数据表的目的。

-- 视图的课堂练习
-- 针对 emp ,dept, 和 salgrade 张三表.创建一个视图 emp_view03,
-- 可以显示雇员编号,雇员名,雇员部门名称和 薪水级别[即使用三张表,构建一个视图]/*分析: 使用三表联合查询,得到结果将得到的结果,构建成视图*/
CREATE VIEW emp_view03ASSELECT empno, ename, dname, gradeFROM emp,dept, salgradeWHERE emp.deptno = dept.deptno AND(sal BETWEEN losalAND hisal)DESC emp_view03SELECT * FROM emp_view03

1.37 Mysql 管理

1.37.1 Mysql 用户

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

其中user表的重要字段说明:
1. host: 允许登录的“位置”,localhost表示该用户只允许本机登录,也可以指定ip地址,
        比如:192.168.1.100
2. user:    用户名;
3. authentication_string: 密码,是通过mysql的password()函数加密之后的密码。

1.37.2 创建用户

create user ‘用户名’ @’ 允许登录位置’ identified by ‘密码’
说明: 创建用户,同时指定密码

1.37.3 删除用户

        drop user ‘用户名’ @ ’允许登录位置’;

1.37.4 用户修改密码

修改自己的密码:
set password = password(密码');
修改他人的密码(需要有修改用户密码权限):
set password for '用户名'@'登录位置' = password('密码');

1.37.5 mysql 中的权限

1.37.6  给用户授权

1.37.7 回收用户授权

基本语法:
revoke 权限列表 on 库.对象名 from  '用户名" @ "登录位置';

1.37.8 权限生效指令

如果权限没有生效,可以执行下面命令.
基本语法:        FLUSH  PRIVILEGES;

1.37.9 练习

-- 演示 用户权限的管理-- 创建用户 zak 密码 123, 从本地登录
CREATE USER 'zak' @ 'localhost' IDENTIFIED BY '123'-- 使用root 用户创建 testdb ,表 newsCREATE DATABASE testdbCREATE TABLE news(id INT ,content VARCHAR(32));-- 添加一条测试数据
INSERT INTO news VALUES(100, '北京新闻');SELECT * FROM news;-- 给 zak 分配查看 news 表和 添加news的权限
GRANT SELECT,INSERTON testdb.newsTO 'zak' @ 'localhost'-- 可以增加update权限
GRANT UPDATEON testdb.newsTO 'zak' @ 'localhost'-- 修改 zak 的密码为 abc
SET PASSWORD FOR 'zak' @ 'localhost' = PASSWORD('abc');--回收 zak 用户在testdb.news表的所有权限
REVOKE SELECT,UPDATE,INSERT ON testdb.news FROM 'zak' @ 'localhost'REVOKE ALL ON testdb.news FROM 'zak' @ 'localhost'--删除 zak DROP USER 'zak' @ 'localhost'

1.37.10 细节说明

1. 在创建用户的时候,如果不指定Host,则为%,%表示表示所有IP都有连接权限create user xXx;
2. 你也可以这样指定
create user 'xxx' @ '192.168.1.%’ 表示Xxx用户在192.168.1.* 的 ip 可以登录mysql
3. 在删除用户的时候,如果 host 不是%,需要明确指定‘用户 '@' host 值'

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/325453.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

网络工程师练习题

网络工程师练习题 网桥怎样知道网络端口连接了那些网站?如果从端口收到一个数据帧,则将其源地址记入该端口的数据库当网桥连接的局域网出现环路时怎么办?运行生成树协议阻塞一部分端口。使用IEEE 802.1q协议,最多可以配置4094个VLAN。VLAN中继协议(VTP)有不同的工作模式,…

深度学习--DCGAN

代码之后的注释和GAN的一样&#xff0c;大家如果已经掌握GAN&#xff0c;可以忽略掉哦&#xff01;&#xff01;&#xff01; 在学习DCGAN之前&#xff0c;我们要先掌握GAN&#xff0c;深度学习--生成对抗网络GAN-CSDN博客 这篇博客讲的就是GAN的相关知识&#xff0c;还是很详…

JVM之运行时数据区

Java虚拟机在运行时管理的内存区域被称为运行时数据区。 程序计数器&#xff1a; 也叫pc寄存器&#xff0c;每个线程会通过程序计数器记录当前要执行的字节码指令的地址。程序计数器在运行时是不会发生内存溢出的&#xff0c;因为每个线程只存储一个固定长度的内存地址。 JAVA虚…

51基于单片机的温室大棚系统设计

设计摘要&#xff1a; 本设计旨在基于51单片机和蓝牙技术&#xff0c;实现一个功能完善的温室大棚系统。该系统具备以下主要功能&#xff1a;首先&#xff0c;通过连接的显示屏能够实时地显示当前的温度和湿度信息&#xff0c;方便用户了解温室内的环境变化。其次&#xff0c;…

Neo4j 之安装和 CQL 基本命令学习

正常使用结构化的查询语言 SQL&#xff08;Structured Query Language&#xff09;较多一些&#xff0c;但是像 Neo4j 这种非结构化的图形数据库来说&#xff0c;就不得不学习下 CQL&#xff08;Cypher Query Language&#xff09;语言了。如果你之前学过 《离散数学》或《图论…

使用SPI驱动串行LCD的驱动实现(STM32F4)

目录 概述 1. 硬件介绍 1.1 ST7796-LCD 1.2 MCU IO与LCD PIN对应关系 2 功能实现 2.1 使用STM32Cube配置Project 2.2 STM32Cube生成工程 3 代码实现 3.1 SPI接口实现 3.2 LCD驱动程序实现 3.3 测试程序实现 4 测试 源代码下载地址&#xff1a; https://gitee.com/mf…

常用Linux命令详细总结

一、文档编辑、过滤、查看命令 1、cp 复制文件和目录 -a 复制文件并保持文件属性 -d 若源文件为链接文件&#xff0c;则复制链接文件属性而非文件本身 -i 覆盖文件前提示&#xff0c;如果不要提示&#xff0c;在命令前加上\ -r 递归复制&#xff0c;通常用于目录的复制 …

C++的数据结构(三):栈

栈&#xff08;Stack&#xff09;是一种后进先出&#xff08;LIFO, Last In First Out&#xff09;的数据结构&#xff0c;它只允许在一端&#xff08;称为栈顶&#xff09;进行插入和删除操作。栈的这种特性使得它在解决函数调用、括号匹配、表达式求值等问题时具有天然的优势…

SpringCloud 2023.0.1

本文介绍如何使用 springboot3及cloud2023 进行微服务模块化开发 采用父-module 模块开发 父工程 demo-java pom.xml <!--配置 springboot的依赖的版本号, 方便 module 进行继承--><dependencyManagement><dependencies><!--增加 springboot的依赖--&g…

宝塔安装多个版本的PHP,如何设置默认的PHP版本

如何将默认的PHP版本设置为7.3.32&#xff0c; 创建软链接指向7.3版本&#xff0c;关键命令&#xff1a;ln -sf /www/server/php/73/bin/php /usr/bin/php 然后再查看PHP版本验证一下结果 [rootlocalhost ~]# ln -sf /www/server/php/73/bin/php /usr/bin/php [rootlocalho…

zabbix“专家坐诊”第238期问答

问题一 Q&#xff1a;请问一下 zabbix 如何监控服务器端口的出和入流量?就类似iftop这样的。 A&#xff1a;可以用snmp去监控。 问题二 Q&#xff1a;各位有什么工具能导出zabbix主机列表成execl格式吗&#xff1f; A&#xff1a;进mysql&#xff0c;到hostid&#xff0c;然…

WEB后端复习——监听器、过滤器

Listener监听器 是Servlet规范中定义的一种特殊类&#xff0c;它用于监听web应用程序中的ServletContext, HttpSession和ServletRequest等域对象的创建与销毁事件&#xff0c;以及监听这些域对象中的属性发生修改的事件。 注解WebListener 1.ServletContextListener 监听Serv…

Python3 + Appium + 安卓模拟器实现APP自动化测试并生成测试报告

这篇文章主要介绍了Python3 Appium 安卓模拟器实现APP自动化测试并生成测试报告,本文给大家介绍的非常详细&#xff0c;对大家的学习或工作具有一定的参考借鉴价值&#xff0c;需要的朋友可以参考下 本文主要分为以下几个部分 安装Python3 安装Python3的Appium库 安装Andr…

K-CU12和利时工控单元

K-CU12和利时工控单元。控制策略组态&#xff0c;使用专用的组态软件 人机界面HMI设计&#xff1a;操作员站画面设计&#xff0c;使用专用的组态软件 K-CU12和利时工控单元文件组态 2文档管理软件 在工程师站上进行系统组态的主要工作&#xff1a; K-CU12和利时工控单元。系统配…

【全开源】Fastflow工作流系统(源码搭建/上线/运营/售后/维护更新)

一款基于FastAdminThinkPHP开发的可视化工作流程审批插件&#xff0c;帮助用户基于企业业务模式和管理模式自行定义所需的各种流程应用&#xff0c;快速构建企业自身的流程管控体系&#xff0c;快速融合至企业协同OA办公系统。 提供全部无加密服务端源码和前端源代码&#xff0…

如何在 Linux / Ubuntu 上下载和安装 JMeter?

Apache JMeter 是一个开源的负载测试工具&#xff0c;可以用于测试静态和动态资源&#xff0c;确定服务器的性能和稳定性。在本文中&#xff0c;我们将讨论如何下载和安装 JMeter。 安装 Java&#xff08;已安装 Java 的此步骤可跳过&#xff09; 安装 Java 要下载 Java&…

【计算机网络篇】数据链路层(10)在物理层扩展以太网

文章目录 &#x1f354;扩展站点与集线器之间的距离&#x1f6f8;扩展共享式以太网的覆盖范围和站点数量 &#x1f354;扩展站点与集线器之间的距离 &#x1f6f8;扩展共享式以太网的覆盖范围和站点数量 以太网集线器一般具有8~32个接口&#xff0c;如果要连接的站点数量超过了…

使用Three.js绘制快速而逼真的水

本文将利用GPUComputationRenderer来实现水波纹的绘制&#xff0c;相似的案例可以看threejs官方的GPGPU Water示例。更多精彩内容尽在数字孪生平台。 什么是 GPGPU GPGPU代表通用图形处理单元&#xff08;General-Purpose Graphic Processing Unit&#xff09;&#xff0c;意思…

从0开始linux(2)——热键、如何查阅手册

欢迎来到博主的专栏——从0开始linux 博主ID&#xff1a;代码小豪 博主使用的linux发行版&#xff1a;CentOS 7.6 文章目录 热键[Tab]热键Ctrl cshift[pageup]和[pagedown] 查阅手册\-\-help在线手册maninfo手册 热键 我们的命令行模式中存在很多的组合热键&#xff0c;这些按…

神经网络中的算法优化(皮毛讲解)

抛砖引玉 在深度学习中&#xff0c;优化算法是训练神经网络时至关重要的一部分。 优化算法的目标是最小化&#xff08;或最大化&#xff09;一个损失函数&#xff0c;通常通过调整神经网络的参数来实现。 这个过程可以通过梯度下降法来完成&#xff0c;其中梯度指的是损失函数…