一、MySql(MariDB)

  • 学习数据库主要学习的是如何对数据进行增删改查操作.
  • Mysql菜鸟教程:【https://www.runoob.com/mysql/mysql-tutorial.html】

1、安装与卸载

00.删除需要管理员权限的文件

删除文件时,提示你需要管理员权限才可以删除,下面是一个简单方法:
————>右键点击桌面的sindows图标
————>选择dos窗口"windows 终端(管理员)"
————>用 【cd 路径】进入一个目录
————>进入路径后,用【dir】查看该目录下的所有文件
————>找到自己想删除的的文件:【del 文件名】
————>即可删除成功!

01.安装步骤

  • 进入网址 http://doc.canglaoshi.org/
  • ——>常用下载:Windows必备
  • ——>MariaDB 10.5.13 WinX64(MySQL) 官网下载
0、安装完成后启动:【在mysql客户端的黑窗口运行该指令】:数据库常见指令:
一、MySQL 连接本地数据库,用户名为“root”,密码“root”(注意:“-p”和“root”之间不能有空格)    例:【mysql -u root -proot   若不写-p后的root则需要回车输入密码】    ————>> 需要在Mysql数据库的【bin】目录下执行此命令才可 <<————    我的bin目录的路径是:D:\soft\01Java\00soft\ruanjian\MariaDB\danei\bin     例如执行以下指令进行连接:    先【win+R ——> cmd】进入dos窗口    先输入【d:】进入D盘,    再输入【cd D:\soft\01Java\00soft\ruanjian\MariaDB\danei\bin 】进入bin目录    再输入【mysql -h localhost -u root -proot】或【mysql -u root -proot】来连接本地数据库。        二、MySQL 连接远程数据库(xxx.xxx.0.xxx),端口“3306”,用户名为“root”,密码“123”    C:>mysql -h xxx.xxx.0.xxx -P 3306 -u root -p123    三、MySQL 连接本地数据库,用户名为“root”,隐藏密码    C:>mysql -h localhost -u root -p    Enter password:    四、MySQL 连接本地数据库,用户名为“root”,指定所连接的数据库为“test”   C:>mysql -h localhost -u root -p123 -D test    mysql>select database();五、查看版本    mysql>status;

02.卸载步骤

MySQL数据库是一款非常好用的数据库管理系统,
但是相对来说卸载起来麻烦一些
这里给大家分享下MySQL数据库如何卸载干净~

(1)停止MySQL的所有服务

就像一个正在使用中的文件是无法删除的一样
我们想要卸载MySQL,首先就需要把计算机中MySQL相关的所有服务都停止。
给大家提供两种方式:方式一:
我的电脑——>
右键"管理"——>
选择"服务和应用程序"——>
继续选择"服务"——>
将页面中所有MySQL相关的服务逐一的全部关闭: 找到mysql服务,右键停止服务方式2:
win+R键打开运行窗口,
输入“cmd”,
点击“确定”或直接回车,
输入命令 net stop mysql 回车————>这个命令的作用也是关闭MySQL的所有服务

(2)卸载MySQL程序

右键“此电脑”
————>选择“属性”
————>点击“控制面板主页”
————>在打开的页面中选择“卸载程序”
————>Mysql相关的全部卸载

(3)删除电脑上的MySQL文件

删除MySQL安装目录文件夹:
如果安装位置是默认位置,一般为 C:\ProgramData\MySQL: SQL数据库数据存放文件(用户自己设定的路径)

(4)删除电脑上MySQL注册表的相关信息

1、杀出注册表
01.用“Win+R”快捷键打开运行窗口,输入“regedit”
02.在打开的注册表编辑器页面,用“Ctrl+F”查找所有关于“MySQL”的注册表,全部删掉2、删除注册表:
我的电脑->HKEY_LOCAL_MACHINE->SYSTEM->ControlSet001-> Services->Eventlog->Applacion->MySQL
我的电脑->HKEY_LOCAL_MACHINE->SYSTEM->ControlSet002-> Services->Eventlog->Applacion->MySQL
我的电脑->HKEY_LOCAL_MACHINE->SYSTEM->CurrentControlSet-> Services->Eventlog->Applacion->MySQL

(5)删除电脑C盘MySQL相关文件夹

如果有的话就删除,没有此步骤跳过将C:\Documents and Settings\All Users\Application Data\MySQL 下的文件夹删除,该文件夹有可能是隐藏的,需设为可见后才能删除。
以上MySQL就卸载完成啦,可以重启电脑后再安装MySQL.

2.1、SQLyog可视化工具

00.安装

 - SQLyog下载地址: https://sqlyog.en.softonic.com/
——————————————————————————————————————————————————————————————
《安装步骤》:SQLyog安装非常简单,基本上是傻瓜式安装.
————>进入以上网站后,点击【Free Download】
————>下载后会得到【SQLyog-13.1.6-0.x64Community.exeT】安装文件
————>使用管理员身份安装,出现【选择组件时只选择桌面图标即可,见下图:】
————>这里我安装到D:\program|SQLyog Community目录下【根据自己的情况来指定目录】
————>双击运行,配置连接

01.使用详解:

1.创建数据库(UTF8字符集)

第一步,右键文件,点击新连接

第二步,填写数据库名称等:

第三步,创建数据库:右键点击创建数据库,输入数据库名和字符集

UTF8字符集:

  • 目前utf8 和utf8mb3 一样 ,代表的是 用3个字节表示一个字符 (mb3=most byte 3)
  • utf8mb4 最多不超过4个字节表示一个字符

第四步,查询表格:选中自己写的sql语句,点击小箭头,即可在下方窗口出现查询的表格

2.0如何备份和还原数据库

2.1 备份数据库的步骤

第一步:右键要备份的数据库->备份/导出->备份数据库。

第二步,在SQL转储界面上根据自己需要进行设置。

1:可根据需要备份数据、结构或者两者。
2:选择备份文件存储的位置。
3:对自己要备份的内容进行勾选。
4:根据自己需要选择写入文件的内容,如Create Database,Use Database等语句。

第三步,点击导出即可。

2.2 还原数据库的步骤

第一步,右键要还原到的数据库->导入->执行SQL脚本。

第二步,在还原数据库界面选择以前备份好的文件。

第三步,点击‘执行’即可。

3.0. 关于数据库表的一些操作

3.1 备份表数据

右键选择某数据库下的表->备份表作为SQL转储。

以下步骤可以参考备份数据库的方法。

3.2 还原表数据

与还原数据库的步骤相同。

3.3 如何查看并修改表结构和索引

第一步,右键表->改变表,打开关于表的详细信息。

第二步,在打开的界面,修改表结构和索引等信息。比如,修改把索引属性修改为FULLTEXT的图如下。

4. 如何创建用户及授权用户对数据库操作

(1)第一种方法:在SQLyog中添加用户并进行授权。

第一步,以root账户的身份创建新连接。
第二步,选择工具->用户管理。

第二步,填写用户名,选择主机localhost或%,输入密码,保存改动即可创建用户。

第三步,
在第二步保存改动后右上角用户即相应的改为iyou@%或iyou@localhost(图中1);
然后再选择要授权的数据库,比如是exjc6(图中2);
接下来通过在具体操作前进行勾选给选择的数据库exjc6进行授予该操作的权利。

第二种方法:在命令窗口中进行创建用户和授权。

使用命令进行数据库授权步骤如下:
@>mysql –u root –p
mysql>grant all privileges on exjc6.* to iyou@’%’ (identified by PASSWORD(‘123’));
mysql>flush privileges;

说明:
all表示所有权限(包括增、删、改、查等权限);
exjc6.
表示对exjc6数据库有所有操作权限, . 表示对所有数据库有所有操作权限;
iyou为添加的用户名;
123为密码;
%为匹配的所有主机,即所有主机都可访问该exjc6数据库,localhost表示匹配本机;
执行完会在mysql.user表插入一条记录,并添加一个名为iyou的用户;
上面的信息可以指定如grant select,update on exjc6. to iyou@localhost identified by '123"。

5. 如何比较两个数据库之间的的差别并进行同步

第一步,选择高级工具->架构同步工具。

第二步,选择要比较的两个数据库,要修改的数据库放在右侧的目标源中。

第三步,
根据需要可以选择仅比较表格或比较全部对象(表、函数、触发器、存储过程等),
然后单击比较,即可出现比较的结果。
结果中通过具体颜色标注出创建或修改的对象,并在左下角显示出具体的内容。

第四步,
点击执行所有,即可把右侧数据库同步成与左侧数据库结构相同的数据库。
需要说明的是这种同步只包含表结构,不包含表数据。

6. SQLyog过期,如何破解

我使用的是SQLyog 9.63,只有一个月的试用期,如何超过了试用期,怎么办?

在这时我可以告诉大家一个解决方案,那就是通过删除注册表项,再获得一个月的试用期。具体的操作方法如下:第一步,运行窗口中输入regedit,回车进入注册表编辑器。第二步,按路径搜索HKEY_CURRENT_USER->SoftWare找到 【红色标注的{dxxxxxxx}d开头的这个文件】后,【删除 再 重启 Sqlyog  即可】。

3.1、关于数据库

数据库(DBMS)简介:【学习数据库阶段内容,主要学习的就是如何对数据进行增删改查操作】

(1)常见DBMS(数据库管理系统)

DataBaseManagementSystem: 数据库管理系统(数据库软件)
常见的几种DBMS:- MySQL:       Oracle公司产品, 08年被Sun公司收购, 09年Sun公司被Oracle收购. 开源产品原MySQL团队从Oracle离职又创建了MariaDB(开源产品),MariaDB实际上就是MySQL的一个分支使用方式和MySQL一样。  市占率第一- Oracle:      Oracle公司产品, 闭源产品 ,性能最强 价格最贵, 市占率排名第二- SQLServer:   微软公司产品, 闭源产品 , 市占率第三  net 编程语言+web服务软件+操作系统+数据库软件- DB2:         IBM公司产品 闭源产品- SQLite:      轻量级数据库, 安装包几十K ,只具备最基础的增删改查功能.

(2)SQL语言

Structured Query Language: 结构化查询语言,通过此语言让程序员和数据库软件进行交流
例:
刘德华    30    5000
insert into emp values("刘德华",30,5000);

(3)数据库常见错误

0.当输入密码时没有进到数据库里,可以点击我的电脑——>右键管理——>服务和应用程序——>服务——>找到mysql——>右键把服务重新打开——>进入mysql客户端重新输入密码——>发现可以登录成功!
1.用户名或密码错误: 检查用户名或密码
2.值的数量 和字段数量不匹配, 检查表的字段是否正确,检查插入的值是否正确

3.主键值重复了

4.值不能为null

5.JDBC链接数据库时的报错: 代表没有启动MySQL服务, 在我的电脑上右键管理 找到Mysql服务右键开启即可

6.个别MySQL版本出现的SSL异常, 在连接数据库的url上面添加&useSSL=false 即可解决

7.SQL语句拼写错误

8.参数位置超出范围, ?的数量和替换问号时

9.插入中文的值时报错(16进制) 问题:

错误原因:  是客户端和MySQL之间编解码字符集不一致导致的
解决方案:  修改MySQL的解码字符集为gbk ——————> 【 set names gbk; 】
如下图:

(4)优化数据库

(5.1)在git上导入样例库 命令

例:mysql样例库:https://gitee.com/mirrors_datacharmer/test_db如何导入样例库?
键盘输入【win+R————>输入cmd】进入【dos窗口的命令行】执行:
:
————> ​cd 解压的文件夹 ​mysql < 解压的文件夹中的employees.sql文件 -uroot -p(例:  cd D:\soft\01Java\00soft\01project\test_db mysql < employees.sql -uroot -p )
————> set PATH=d:\xxxxx\mysql\bin;%PATH%​解压目录> mysql < employees.sql

(5.2)导入" xxx.sql " 文件

(1)把emp.zip解压出来得到一个emp.sql文件, 建议把这个文件放到某个盘的根目录:————> 比如 F盘根目录,然后在mysql黑窗口客户端执行指令:————> 格式:  source 路径;  例:  source f:/danei/Java/emp/emp.sql;
(2)在mysql客户端测试以下SQL语句 检查是否成功:show databases; //检查里面是否多了一个empdb;show tables; //会出现两个表 emp 和deptselect * from emp; //检查是否出现了数据,  如果格式错乱  正常(3)如果出现乱码执行 set names utf8;

3.2、数据库相关:

00.SQL语句(格式/分类)

Structured Query Language: 结构化查询语言, 通过此语言让程序员和数据库软件进行交流
例:【刘德华 30 5000——————>insert into emp values("刘德华",30,5000);】
————————————————————————————————————————————————————————————————————
《SQL语句格式》:- 以;号结尾- 关键字不区分大小写- 可以有空格或换行但一定要以;结尾
————————————————————————————————————————————————————————————————————
《SQL语句分类》
DDL: 数据定义语言,包括数据库相关和表相关的SQL语句:【create 表,库】
DML: 数据操作语言, 包括增删改查:【增加insert 修改update 删除delete 语句】
DQL: 数据查询语言, 只包含【select】查询相关的SQL语句
TCL: 事务控制语言
DCL: 数据控制语言,【管理数据库,比如用户权限 grant授予 revoke撤销】

01.如何连接数据库执行SQL语句?

《如何连接数据库执行SQL语句》:
(1)首先检查本机电脑MySQL服务是否开启?- 通过命令行/终端 和数据库软件建立连接首先检查MySQL/MariaDB服务是否开启:- 在:`我的电脑/此电脑上右键->管理->服务和应用程序->服务->找到`MariaDB`后右键启动(2)执行SQL语句需要先和数据库软件建立链接之后(两种登录Mysql客户端的方式):第一种:- 从开始菜单中找到:`MariaDB或MySQL`,- 然后打开找到里面的客户端:`MySQL Client` 打开 , - 然后`输入密码后回车`- 显示Welcome … 说明建立好了连接- 退出指令: exit- 建立连接登录指令: mysql -uroot -p 回车后输入密码 再回车:C:\Program Files\MariaDB 10.5\bin>mysql -uroot -p  回车Enter password: **** ————>(输入密码)MariaDB [(none)]>    ————>(成功登录到mysql)第二种:在IDEA中:点击界面下面的【Terminal】按钮,(1)首先切换到c盘:执行指令:————————————————>【c:】(2)切换到Mysql数据库的bin目录下————————————>【cd Program Files\MariaDB 10.5\bin】(3)连接数据库的指令————————————————————————>【mysql -uroot -p 回车】(4)此时在IDEA中已经和数据库建立连接了!可以输入sql语句进行对应的操作!

02.数据库三层结构:DBMS/数据库/表

《数据库和表的概念》:
在MySQL数据库软件中保存数据,需要先建库,然后在库里面建表,然后把数据保存到表中
如下图:

《数据库管理系统(DBMS) | 数据库 | 表》所谓安装Mysql数据库,就是在主机安装一个数据库管理系统(DBMS),
这个数据库管理程序[DBMS(database manage system)]可以管理多个数据库。
注:在MySql数据库的dos窗口客户端的bin目录下输入:【netstat -anb】即可发现:mysqld.exe这个程序就在3306端口监听mysqld 这个程序就是DBMS中最核心的程序一个数据库中可以创建多个表,以保存数据(信息)。
!!!——————>【数据库表的本质就是文件】<——————!!!【数据库管理系统(DBMS)、数据库 和 表】 的关系如图所示:
见示意图1 2:


《一个查询语句返回结果的流程》:见上图↑
把sql查询语句通过网络打到数据通道3306这个DBMS服务上,
DBMS拿到这个指令会分析(其实这个指令是发送给mysqld 这个程序的;mysqld.exe这个程序就在3306端口监听mysqld 这个程序就是DBMS中最核心的程序),
分析之后会把其中对应的数据库DB1中对应的表数据返回给客户端

03.数据在数据库中的存储方式:表

  • 在MySQL数据库软件中保存数据, 需要:先建库,然后在库里面建表,然后把数据保存到表中

04.UTF8字符集

目前utf8 和utf8mb3  一样,
代表的是用3个字节表示一个字符(mb3 = most byte 3)utf8mb4: 最多不超过4个字节表示一个字符

05.用户管理指令

(1)创建用户

1、
(1)创建root用户:# 添加允许远程登录的'root'用户(则可以创建'root'@'%'用户,因为['root'@'%':从任意地址都可以登录])【create user 'root'@'%';】
(2)创建普通用户【create user 'test'@'%'】补充:
【'root'@'%'】           :  从任意地址都可以登录
【'root'@'192.168.%'】   : 只能从192.168开头的IP地址登录
【'root'@'192.168.6.15'】: 只能从指定的这台服务器登录# mysql用户有两个字段:用户名、登录的主机地址
root        'localhost'         'root'
root        '192.168.0.5'       'abc123'
root        '192.168.9.%'       '123456'
root        '%'                 '111111'

(2)设置密码

2、 设置密码# 当前用户
set password = password('root');# 指定用户
set password for 'username'@'localhost' = password('123456');

(3)授予最高权限并设置密码

3、 给root用户授予最高权限并设置密码
# 为'root'@'%'用户授予最高权限,密码设置成'root'
# grant select,update,delete,create,drop,truncate on test.a(a,b)
# all privileges 所有权限
# on *.* 所有库所有表
# identified by 'root' 设置该用户的密码
【grant all privileges on *.* to 'root'@'%' identified by 'root';】
​
# 用户授权
# grant    select,insert,update,delete   on    test.*    to   'abc'@'%'
# grant    create,alter,drop             on    db1.*     to   'abc'@'localhost'
# grant    all privileges                on    *.*       to   'abc'@'%'
# grant    select,insert                 on    db1.t1    to   'abc'@'%'
# grant    select(id, name)              on    db1.t1    to   'abc'@'%
grant all privileges on *.* to 'root'@'%';

(4)查询系统用户表

select user,host from mysql.user;

(5)删除用户

drop user 'test'@'%'

06.MySql 5种约束

1、 主键:2、 外键:(1)很多公司禁用外键约束- 数据增删改操作,如果有外键,要到其他表检查数据正确性,有性能损耗- 禁用外键可以提高增删改效率- 不用外键,也可以对数据进行关联查询(2)有的项目也会禁用关联查询- 关联多张表查询效率低- 可以分多次从不同表查询需要的数据- 数据可以适当冗余,提高查询效率3、 非空:4、 唯一:5、 检查:check(age between 3 and 60)check(gender in('M', 'F'))

07.B+Tree:是数据库索引所采用的存储结构

如上图:             B+tree 是对 B-Tree(即B树) 的优化
"磁盘块1"            称为——————>  "根节点"
"磁盘块4 5 6 7 8 9"  称为——————>  "叶子节点"(最下一层,没有子节点的节点叫叶子节点)
"磁盘块2 3"          称为——————>  "非叶子节点"(初根节点和叶子节点外的节点,叫非叶子节点)问:B+Tree 是如何范围查询的?
答:通过范围的下限,去查找到B+tree的叶子节点。找到叶子节点后,再通过叶子节点的链表,进行范围查询,这样性能就很高。B+Tree的特点总结(B-Tree(即B树)的基础上优化了):
1、节点上只存储键值,不存储数据,这样一来,在有限的节点空间(页空间)内就可以存放更多的键值、指针;
2、非叶子节点只存索引信息,所有数据都放在叶子节点中,所有叶子节点之间有链指针(双向循环列表:有序链表),便于范围查找,也便于排序。B+tree的优势:
1、单一节点存储更多的元素,使得查询的IO次数更少。
2、所有查询都要查找到叶子节点,查询性能稳定。
3、所有叶子节点形成有序链表,便于范围查询。B+tree与磁盘IO:在InnoDB(是MySQL的数据库引擎之一,现为MySQL的默认存储引擎)中,默认定义的B+tree的节点大小是16kb,这就是说,假如一个key是8个字节,那么一个节点大约存1000个key,意味着B+树可以有 1000个分叉。同时InnoDB一次磁盘IO,读取的都是16kb的整数倍数据,这样,一次性能读取很多节点的内容出来。B+tree的叶子节点上,所有记录都是按照索引列从小到大的顺序排列,并且形成一个双向链表。在实际读写的时候,很大概率相邻的节点会放在相邻的页上,可以充分利用磁盘顺序IO的高速读写特性(磁盘顺序读写比随机读写性能高很多)。看一下 Mysql的B+tree索引叶子节点 的连接情况(如下图):

08.索引和索引优化

(0)什么是索引?

用来加速查询
加速排序索引:是一种特殊的数据库结构,由数据表中的一列或多列组合而成,可以用来【快速查询】数据表中有某一特定值的记录。

(1)导入Mysql样例库

样例库:【 https://gitee.com/mirrors_datacharmer/test_db 】导入样例库:
# 进入解压的目录执行:
# 地址换成你的服务器地址mysql < employees.sql -h47.92.222.174 -uroot -p如果找不到mysql命令,需要在path环境变量中添加mysql的bin目录路径:set PATH=d:\xxxxx\mysql\bin;%PATH%解压目录> mysql < employees.sql

(2)索引的:创建/查看/删除

-- 创建索引:【 create index 索引名称 on 表名(字段名); 】【 create index 索引名称 on 表名(字段1, 字段2, 字段3); 】例:select * from employees where first_name='Georgi';create index emp_first_name_index on employees(first_name);# 创建两个字段的组合索引create index emp_last_name_gender_index on employees(last_name, gender);-- 查看索引:【show index from 表名;】show index from employees;
-- 例:按 last_name,gender 来过滤查询员工-- 加索引前,250毫秒-- 加索引后,0毫秒EXPLAINSELECT * FROM employees WHERE last_name='Facello' AND gender='M';EXPLAIN SELECT * FROM employees WHERE last_name='Facello';-- 删除索引:drop index on 表名

(3)索引失效的原因:

①最左前缀原则

过滤条件中,
使用索引中最左侧字段作为第一个条件,后面按索引字段顺序设置过滤条件,
否则可能造成索引失效
——————————————————————————————————————————————————————————————————————————
drop index emp_first_name_index on employees;
drop index emp_last_name_gender_index on employees;
CREATE INDEX employees_flh_index ON employees(first_name,last_name,hire_date);# 覆盖索引,只查询索引字段,从索引中获取数据,不用返回表中取数据
EXPLAIN
SELECT first_name,last_name,hire_date
FROM employees;# 覆盖索引,索引中也会保存主键值
EXPLAIN
SELECT emp_no,first_name,last_name,hire_date
FROM employees;# 使用索引来过滤fist_name,但需要回表获取birth_date字段
EXPLAIN
SELECT first_name,last_name,hire_date,birth_date
FROM employees
WHERE first_name='Georgi';# 索引覆盖,不用回表取数据
EXPLAIN
SELECT first_name,last_name,hire_date
FROM employees
WHERE first_name='Georgi';# 违反最左前缀,索引失效,回表扫描
# 过滤条件中,必须有第一个字段作为过滤条件
EXPLAIN
SELECT first_name,last_name,hire_date,birth_date
FROM employees
WHERE last_name='Facello' AND hire_date='1986-06-26';# 索引覆盖
# 只查询索引字段,全索引扫描,不需要回表
EXPLAIN
SELECT first_name,last_name,hire_date
FROM employees
WHERE last_name='Facello' AND hire_date='1986-06-26';# 满足最左前缀,三个条件按索引顺序来设置
EXPLAIN
SELECT first_name,last_name,hire_date,birth_date
FROM employees
WHERE first_name='Georgi' AND last_name='Facello' AND hire_date='1986-06-26';# 覆盖索引
EXPLAIN
SELECT first_name,last_name,hire_date
FROM employees
WHERE first_name='Georgi' AND last_name='Facello' AND hire_date='1986-06-26';# 没有中间的字段
# 使用第一个字段定位一段数据,在这一段数据中再一条条的判断
EXPLAIN
SELECT first_name,last_name,hire_date,birth_date
FROM employees
WHERE first_name='Georgi' AND hire_date='1986-06-26';# 覆盖索引
EXPLAIN
SELECT first_name,last_name,hire_date
FROM employees
WHERE first_name='Georgi' AND hire_date='1986-06-26';

②对索引字段做运算导致索引失效

-- 左侧第一个字段过滤,索引生效EXPLAINSELECT * FROM employeesWHERE first_name='Georgi'-- 对索引字段运算,导致索引失效EXPLAINSELECT * FROM employeesWHERE LEFT(first_name, 3)='Geo'

③使用范围条件索引会失效

-- 范围过滤,索引会失效
EXPLAIN
SELECT *
FROM employees
WHERE first_name<'Geo' AND last_name='Facello' AND hire_date='1986-06-26';EXPLAIN
SELECT *
FROM employees
WHERE first_name BETWEEN 'Geo' AND 'Hzz'

④不等值过滤会索引失效

EXPLAIN
SELECT first_name last_name,hire_date,gender
FROM employees
WHERE first_name<>'Georgi'

⑤mysql低版本中,空值过滤会使索引失效

-- 查看表结构
DESC employees;-- hire_date允许null
ALTER TABLE employees MODIFY
hire_date DATE NULL;-- 100001员工的hire_date设置成null
UPDATE employees SET hire_date=NULL WHERE emp_no=100001;SELECT * FROM employees WHERE emp_no=100001;-- 创建hire_date字段的索引
CREATE INDEX emp_hire_date_index ON employees(hire_date);-- 用入职时间过滤,索引有效
EXPLAIN
SELECT * FROM employees WHERE hire_date='1985-02-18';-- 用null值过滤,新版本mysql不会失效,低版本会失效
EXPLAIN
SELECT * FROM employees WHERE hire_date IS NULL;

⑥like 通配符放在前面会索引失效

EXPLAIN
SELECT first_name,last_name,hire_date,gender
FROM employees
WHERE first_name LIKE '%en%';EXPLAIN
SELECT first_name,last_name,hire_date,gender
FROM employees
WHERE first_name LIKE 'En%';EXPLAIN
SELECT first_name,last_name,hire_date,gender
FROM employees
WHERE first_name LIKE '_en%';EXPLAIN
SELECT first_name,last_name,hire_date
FROM employees
WHERE first_name LIKE '_en%';

⑦or 过滤

-- 低版本mysql会失效,高版本不失效
EXPLAIN
SELECT *
FROM employees
WHERE first_name='Georgi' OR first_name='Kendra';

(4)explain结果解释

1 、select_type:

  • SIMPLE 简单的SELECT查询,查询中不包含子查询或者UNION
  • PRIMARY 查询中如果包含任何复杂的子部分,最外层查询则被标记为PRIMARY
  • SUBQUERY 在SELECT或者WHERE子句中包含的子查询。
  • DERIVED 如果一个查询在FROM子句中包含子查询,则该查询被标记为DERIVED(衍生),MySQL会递归执行这些子查询,把结果放在临时表中。
  • UNION 如果第二个SELECT出现在UNION之后,则被标记为UNION;若UNION包含在FROM子句的子查询中,外层SELECT将被标记为DERIVED。
  • UNION RESULT 从UNION表获取结果的SELECT。

2、type

访问类型从最好到最差依次是:  system>const>eq_ref>ref>range>index>ALL。
除了ALL没有用到索引,其他级别都用到索引了。
  • system 表只有一行记录(等于系统表),这是const类型的特例,平时不会出现,这个也可以忽略不计。
  • const 表示通过索引一次就找到了,const用于比较primary
    key或者unique索引。因为只匹配一行数据,所以很快。如将主键置于where列表中,MySQL就能将该查询转化为一个常量。
  • eq_ref 唯一性索引扫描,读取本表中和关联表表中的每行组合成的一行,查出来只有一条记录。除了 system 和 const
    类型之外, 这是最好的联接类型。
  • ref 非唯一性索引扫描,返回本表和关联表某个值匹配的所有行,查出来有多条记录。
  • range 只检索给定范围的行,一般就是在WHERE语句中出现了BETWEEN、< >、in、like等的查询。这种范围扫描索引比全表扫描要好,因为它只需要开始于索引树的某一点,而结束于另一点,不用扫描全部索引。
  • index Full Index Scan,全索引扫描,index和ALL的区别为index类型只遍历索引树。也就是说虽然ALL和index都是读全表,但是index是从索引中读的,ALL是从表中读取的。
  • ALL Full Table Scan,没有用到索引,全表扫描。

3、possible_keys

显示可能应用在这张表中的索引,一个或者多个。
查询涉及到的字段上若存在索引,则该索引将被列出,但不一定被查询实际使用。

4、key

实际使用的索引。如果为NULL,则没有使用索引。
查询中如果使用了覆盖索引,则该索引仅仅出现在key列表中。

5、key_len

表示索引中使用的字节数,可通过该列计算查询中使用的索引的长度。
key_len  显示的值为索引字段的最大可能长度,并非实际使用长度,即key_len是根据表定义计算而得,不是通过表内检索出的。在不损失精度的情况下,长度越短越好。

6、ref

显示索引的哪一列被使用了,如果可能的话,是一个常数。哪些列或常量被用于查找索引列上的值。

7、rows

根据表统计信息及索引选用情况,大致估算出找到所需的记录需要读取的行数。

8、Extra

包含不适合在其他列中显示但十分重要的额外信息。
  • Using filesort
    说明MySQL会对数据使用一个外部的索引排序,而不是按照表内的索引顺序进行读取。MySQL中无法利用索引完成的排序操作成为"文件内排序"。
  • Using temporary 使用了临时表保存中间结果,MySQL在対查询结果排序时使用了临时表。常见于排序order by和分组查询group by。临时表対系统性能损耗很大。
  • Using index 表示相应的SELECT操作中使用了覆盖索引,避免访问了表的数据行,效率不错!如果同时出现Using where,表示索引被用来执行索引键值的查找;如果没有同时出现Using where,表明索引用来读取数据而非执行查找动作。
  • using index condition 索引下推
  • Using where 表明使用了WHERE过滤,回到server执行过滤
  • Using join buffer 使用了连接缓存。
  • impossible where WHERE子句的值总是false,不能用来获取任何元组。

(5)索引下推

mysql5.7后,复合索引的过滤条件,第一个之后的条件直接在存储引擎中执行过滤,而不回到Mysql Server执行(using index condition)

(6)聚簇索引和非聚簇索引

《聚簇索引》:直接和表数据存储在一起的索引。聚簇索引(聚集索引):并不是一种单独的索引类型,而是一种数据存储方式。具体细节取决于不同的实现,InnoDB的聚簇索引其实就是在同一个结构中保存了B-Tree索引(技术上来说是B+Tree)和数据行。主键
如果没有主键使用唯一索引
如果没有唯一索引,使用隐藏字段rowid
————————————————————————————————————————————————————————————————
《非聚簇索引》:和表数据分开,单独存储。
除了聚簇索引,其他索引都是非聚簇索引。
(1)非局促索引中保存:- 索引字段的数据- 聚簇索引的数据
(2)非聚簇索引过滤查询数据:- 在索引中找到过滤的数据- 使用主键值,在聚簇索引中找到主键数据- 通过主键数据,从表中取出整行数据

(7)回表

通过索引定位到数据,然后回到表中获取整行数据。
如果有索引覆盖,就不需要回表,从索引就可以取出所有要查询的数据

那么不用主键索引就一定需要回表吗?
不一定!
如果查询的列本身就存在于索引中,那么即使使用二级索引,一样也是不需要回表的。
举个例子,我有如下一张表:

uname 和 address 字段组成了一个复合索引,那么此时,虽然这是一个二级索引,但是索引树的叶子节点中除了保存主键值,也保存了 address 的值。
我们来看如下分析:

可以看到,此时使用到了 uname 索引,但是后的 Extra 的值为 Using index,
这就表示用到了索引覆盖扫描(覆盖索引),此时直接从索引中过滤不需要的记录并返回命中的结果,
这一步是在 MySQL 服务器层完成的,并且不需要回表。

09.三范式

(1.1)第一范式:确保每列的原子性

第一范式:确保每列的原子性(就是每个字段都不可在拆分的最小单元),当然拆分也要有度。(数据库表的每一列都是不可分割的基本数据项,同一列中不能有多个值,即实体中的某个属性不能有多个值或者不能有重复的属性存在传递函数依赖关系。)
比如下面 把地址拆分出了国家和城市,这就满足了第一范式:思考:地址包含省、市、县、地区是否需要拆分?如果仅仅起地址的作用,不需要统计,可以不拆分;如果有按地区统计的功能则需要拆分。根据自身项目需求决定

(1.2)第二范式:非键字段必须依赖于键字段

第二范式:非键字段必须依赖于键字段(在满足第一范式的前提下,要求每个表只描述一件事情)。(每个非关键字列都独立于其他非关键字列,并依赖于关键字,第三范式数据库中不能。)

比如下面 订单编号跟订单日期有关系,产品编号和价格有关系,所以写在一起不合理:

如果感觉上图比较难理解,那就看下面的图:

(1.3)第三范式:消除传递依赖

第三范式:消除传递依赖(在满足第二范式的前提下,除了主键以外的其他列消除传递依赖)(完全依赖于主键,消除非主属性对主码的部分函数依赖。)

比如下面 既然有了顾客编号了,那顾客姓名显然就有点冗余(因为完全可以根据顾客编号得到顾客姓名)

如果感觉上图比较难理解,那就看下面的图:

语文和数学确定了,总分就确定了,所以不满足第三范式:

(2)为什么有时候要反三范式?

范式越高,数据冗余越少,但是效率有时就越地下,为了提高运行效率,可以适当让数据冗余。问:就如上图学生总分这个表,明明没有满足第三范式,那他就是这么设计的为什么?
答:因为如果当查询这个总分数访问量比较大时,这时候就是性能更重要。当性能和规范化冲突的时候,我们首选性能。这就是“反三范式”。

(3)三范式总结:

范式越高,数据冗余越少,效率越低
范式越低,数据冗余越多,效率越高1、第一范式约束的所有字段
2、第二范式约束的主键和非主键的关系
3、第三范式约束的非主键之间的关系
4、范式越高,冗余越少,但表也越多。
5、规范化和性能的关系 <——————> 性能比规范化更重要

10.搭建Mysql主从

主从:
指的是建立两个完全一样的数据库,
其中一个作为主要使用的数据库,另一个作为次要的数据库,
可以【防止因数据库服务器宕机导致数据丢失,还能提供故障切换、读写分离和备份的功能】。主从复制、双机热备。
主从服务器先各自安装Mysql。

(1)主机配置

1、 修改配置文件vim /etc/my.cnf.d/server.cnf
# 在 [mysqld] 条目下添加内容:# 启用二进制日志,记录操作日志log_bin=mysql-bin# 不同步mysql系统数据库binlog_ignore_db=mysqlbinlog_ignore_db=testbinlog_ignore_db=information_schema# 数据库集群中的每个节点id都要不同,一般使用IP地址的最后段的数字,例如172.30.11.12,server_id就写12server_id=12
————————————————————————————————————————————————————————————————————————————————————
2、 重启主机的Mysql服务systemctl restart mariadb
————————————————————————————————————————————————————————————————————————————————————
3、 在主机中对从机进行授权# 在主服务器中创建用户,这个用户用于从服务器连接主服务器
mysql -uroot -pCREATE USER 'slave1'@'%' IDENTIFIED BY 'slavepwd';GRANT REPLICATION SLAVE ON *.* TO 'slave1'@'%';flush privileges;
————————————————————————————————————————————————————————————————————————————————————
4、 备份主机数据库,并复制到从机mysqldump -uroot -proot --all-databases > dump.sql# ssh copy
scp dump.sql 172.23.122.89:/root/

(1)从机配置

1、 修改从机配置文件:vim /etc/my.cnf.d/server.cnf
# 在 [mysqld] 条目下添加内容:server_id=229# 重启maraidbsystemctl restart mariadb
————————————————————————————————————————————————————————————————————————————————————
2、 导入数据:mysql -uroot -proot < dump.sql
————————————————————————————————————————————————————————————————————————————————————
3、 启动从机复制mysql -uroot -pchange master to master_host='172.23.122.88',master_user='slave1',master_password='slavepwd';start slave;
————————————————————————————————————————————————————————————————————————————————————
4、 查看从机状态:show slave status\G
————————————————————————————————————————————————————————————————————————————————————
5、 可能出现的问题(1)如果是slave_io_running:no肯定是因为log文件或者pos位置跟主服务器不对应导致的;解决办法:修改从服务器与主服务器一致即可,每次主服务器的sql操作都会影响pos位置,主从服务器的pos同时改变;stop slave;  #关闭服务
change  master to master_log_file='主服务器的文件', MASTER_LOG_POS=0;
start slave; #开启服务
show slave status\G;  #查看状态是否为yes
——  ——  ——  ——  ——  ——  ——  ——  ——  ——  ——  ——  ——  ——  ——  ——  ——  ——  ——  ——  ——
(2)查看master_log_file和MASTER_LOG_POS可以在主机执行:show master status;如果是slave_sql_running:no
一般是因为执行sql语句时发生错误导致,这种错误有很多触发方式,在此不一一列举:
解决办法:
1、简单粗暴:关闭服务->跳过一条记录->启动服务->查看是否为yes,否:再次跳过一条记录直到yes为止stop slave;
SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1;
start slave;
show slave status\G

(3)测试:

#主机执行:
create database db1 charset utf8mb4;
use db1;
create table my_tb1(a int);
insert into my_tb1 values(1);
insert into my_tb1 values(2);
insert into my_tb1 values(3);#从机执行:
use db1;
show tables;select * from my_tb1;

11.Mysql日志

(1)日志分类

错误日志:  记录mysql服务的启动,运行或停止时出现的问题;
查询日志:  记录建立的客户端连接和执行的语句;
二进制日志:记录所有更改数据的语句,可以用于数据的复制;
慢查询日志:记录所有执行时间超过long_query_time的所有查询或不使用索引的查询;

(2)错误日志 log_error

在mysql数据库中,错误日志功能是默认开启的。
默认情况下,错误日志存储在mysql数据库的数据目录中。错误日志文件通常的名称为hostname.err。其中,hostname表示服务器主机名。
错误日志信息可以自己进行配置,错误日志所记录的信息是可以通过log-error和log-warnings来定义的,其中log-error是定义是否启用错误日志的功能和错误日志的存储位置,log-warnings是定义是否将警告信息也定义至错误日志中。

默认情况下错误日志大致记录以下几个方面的信息:

  • 服务器启动和关闭过程中的信息(未必是错误信息,如mysql如何启动InnoDB的表空间文件的、如何初始化自己的存储引擎等);
  • 服务器运行过程中的错误信息;
  • 事件调度器运行一个事件时产生的信息;
  • 在从服务器上启动服务器进程时产生的信息;

(3)启用错误日志

错误日志在默认情况下是被激活的。
这个选项决定了错误日志的写入名称:[log-error=filename](https://mariadb.com/kb/en/server-system-variables/#log_error) 如这里没有指派文件名,系统的错误日志将会写入到*host-name*.err 中。如果没有指派绝对路径,系统的错误日志文件将会写入到数据目录中,
这个位置由:[datadir](https://mariadb.com/kb/en/server-system-variables/#datadir) 系统变量决定。
————————————————————————————————————————————————————————————————————————————
《编辑mysql配置文件》:  vim /etc/my.cnf.d/server.cnf
————————————————————————————————————————————————————————————————————————————
《添加配置》:
在[mysqld]配置项下面添加:
#### 日志文件名可以任意命名
log_error=mysqld.err
————————————————————————————————————————————————————————————————————————————
《重启mariadb》:  systemctl restart mariadb
————————————————————————————————————————————————————————————————————————————

(4)查看日志

# 查看有没有生成错误日志文件cd /var/lib/mysql/ll# 查看文件内容tail -f /var/lib/mysql/mysqld.err

(5)切换到新的日志文件

cd /var/lib/mysqlmv mysqld.err mysqld.err.oldmysqladmin -uroot -proot flush-logs

(6)二进制日志 log_bin

主要记录MySQL数据库的变化,
二进制日志以一种有效的格式,并且是事务安全的方式包含更新日志中可用的信息。
二进制日志包含所有更新的数据或者已经潜在更新的数据。
二进制日志还包含:关于每个更新数据库的语句的执行时间,它不包含没有修改任何数据的语句。
使用二进制日志的主要目的:是最大可能地恢复数据库。

(7)启用二进制日志

《默认情况下二进制日志是关闭的》
编辑mysql配置文件:
vim /etc/my.cnf.d/server.cnf
——————————————————————————————————————————————————————————————————————
《在[mysqld]配置项下面,可以添加的配置》:#打开二进制日志,后面是名字。
#具体文件名:
# mysql-bin.000001
# mysql-bin.000002
# mysql-bin.000003
log_bin=mysql-bin#在主从配置中服务器id必须唯一,必须和log-bin搭配才可以生效。
server_id=1#清除日志的天数
expire_logs_days=10#单个日志文件的大小限制,超出会新建一个,默认为1GB
max_binlog_size=100M# 重启服务
systemctl restart mariadb

(8)查看日志文件

直接查看:
SHOW BINARY LOGS或者到数据目录中查看:
cd /var/lib/mysql
ls

(9)删除日志

# 删除指定文件之前的日志文件
# 即删除1、2, 保留3、4、5...purge master logs to 'mysql-bin.000003';# 删除指定时间之前的日志文件PURGE MASTER LOGS BEFORE '2022-09-24 21:44:00';# 删除所有二进制日志,并生成一个新的二进制文件,从1开始reset master;

(10)使用二进制日志恢复数据

如果MySQL服务器启用了二进制日志,可以使用二进制日志还原数据库。
还原方式:- 使用最后一次备份还原- 指定时间段恢复数据
示例:mysqlbinlog mysql-bin.000002 mysql -uroot -prootmysqlbinlog后面可以添加选项:--start-datetime:开始时间--stop-datetime:结束时间--stop-position:结束位置

(11)暂停记录二进制日志

只能在session级别暂停日志记录:
set session sql_log_bin=0;

(12)慢查询日志

慢查询日志用于记录那些已经执行完成但是执行时间过慢的DML语句(也可以通过配置打开DDL语句的记录)。

这些被记录的语句都是自身执行过慢的语句,而不包含锁等待时间。

慢查询日志采用的是简单的文本格式,可以通过各种文本编辑器查看其中的内容。其中记录了语句执行的时刻,执行所消耗的时间,执行用户,连接主机等相关信息。

慢查询之所以会出现基本上归咎于两点:查询语句过于复杂、索引覆盖不全。

慢查询日志可以查找出哪些查询语句的执行效率较低,以便进行优化。一般建议开启。它对服务器性能的影响微乎其微,但是可以记录mysql服务器上执行了很长时间的查询语句。可以帮助我们定位性能问题。

MySQL还提供了专门用来分析慢查询日志的工具程序mysqldumpslow,用来帮助数据库管理人员解决可能存在的性能问题。

数据库性能问题大多数都是由于慢查询语句导致,大量慢查询并发出现时会导致服务器CPU跑高的情况发生,所以慢查询日志可以帮助管理员分析问题所在,起到对SQL进行优化的作用。

优化通常从高到低逐步进行,比如一开始定义超过5秒的算慢语句,然后等把这部分5秒的慢语句都处理完了再降低到4秒,以此类推。在一个慢查询日志中最需要关注执行次数多、执行时间长、IO过高、未命中索引的SQL。

(13)查看慢查询日志配置

查看慢日志是否开启:
SHOW GLOBAL VARIABLES LIKE '%slow_query_log%';查看慢查询的时长定义:
SHOW GLOBAL VARIABLES LIKE '%long_query%';

(14)启用慢查询日志

《命令设置》:# 全局启用慢查询日志SET GLOBAL slow_query_log=1;# 当前会话启用慢查询日志SET SESSION slow_query_log=1;# 定义慢查询时长SET GLOBAL long_query_time=1;
——————————————————————————————————————————————————————————————
《配置文件设置》:  vim /etc/my.cfn.d/server.cnf
——————————————————————————————————————————————————————————————
《添加配置》:#开启慢查询日志
slow_query_log=1
#指定日志文件保存路径,不指定的话默认在数据库文件目录下,名为hostname-slow.log
slow_query_log_file=/usr/local/mysql/data/mysql-slow.log
#指定达到多少秒才算慢查询,设为0代表记录所有查询
long_query_time=2
#如果语句没有使用索引也会被记录,即便没有达到阈值
log_queries_not_using_indexes=1
#如果没有使用索引的SQL执行特别频繁,那每分钟最多只记录60次
log_throttle_queries_not_using_indexes=60
#默认为UTC时间,这样查看日志会存在时区问题,建议修改为SYSTEM,和系统时间一致
log_timestamps=system
# min_examined_row_limit = 1000  #SQL至少要扫描达到指定的行数才记录
# log-slow-admin-statements  #记录由ALTER TABLE等语句引发的慢查询
# log-slow-slave-statements  #记录从服务器产生的慢查询

(15)查看慢 sql 日志

执行两条慢查询:
SELECT SLEEP(3);    //暂停3秒
SELECT SLEEP(7);    //暂停7秒直接查看日志文件:
tail -f mysql-slow.log

4、用java操作MySql

01.第一种方法:java程序操作Mysql 快速创建表

《目标需求》:1.通过此 Java 程序与指定数据库建立连接2.在该数据库中创建 hsp_goods表 ,3.在hsp_goods表中添加数据4.删除该表两种实现方法:
1、《在Mysql中用sql实现》:
2、《用java 程序操作Mysql》:【前提是存在需要建立连接的数据库】——  ——  ——  ——  ——  ——  ——  ——  ——  ——  ——  ——  ——  ——  ——  ——  ——
1、《在Mysql中用sql实现》:# 创建hsp数据库:
create database hsp charset = utf8;
# 创建hsp_goods表格:【introduce:介绍】
create table hsp_goods ( id int, name varchar(32), price double, introduce text);
# 在该表格中插入数据:
INSERT INTO hsp_goods(id,NAME,price,introduce) VALUES (1, '华为手机', 2000, '这是不错的一款手机'),(2, '小米手机', 3000, '这是不错的一款手机'),(3, '苹果手机', 4000, '这是不错的一款手机');
#删除该表格:
drop table hsp_goods;
——  ——  ——  ——  ——  ——  ——  ——  ——  ——  ——  ——  ——  ——  ——  ——  ——
2、《用java 程序操作Mysql》:【前提是存在需要建立连接的数据库】(1)创建maven,在子包里随便创建一个类,在pom.xml里添加下面两个依赖:
<!-- 连接MySQL数据库的依赖 -->
<dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.15</version>
</dependency>
<!-- 数据库连接池 -->
<dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.1.21</version>
</dependency>(2)编写java代码
package cn.tedu.day03;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
/*** 《java 程序如何操作Mysql 连接对应的数据库并快速创建表并插入数据》:* 需求:* 1.通过此 Java 程序与指定数据库建立连接* 2.在该数据库中创建 hsp_goods表 ,* 3.在hsp_goods表中添加数据* 4.删除该表* * 注解:@SuppressWarnings:*      被该注解修饰的程序元素(以及该程序元素中的所有子元素)取消显示指定的编译器警告,*      且会一直作用于该程序元素的所有子元素。*/
@SuppressWarnings({"all"}) //此注解的作用: 抑制所有类型的警告
public class JavaMysql {public static void main(String[] args) throws ClassNotFoundException, SQLException {/** 下面演示一下 java 程序如何操作Mysql:*///首先加载类,和mysql建立连接【前提是有hsp这个数据库:create database hsp charset = utf8;】Class.forName("com.mysql.cj.jdbc.Driver");Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/hsp", "root", "root");/*下面可以编写sql语句: 【包括对表的如下操作:create , select , insert , update ,delete ...】*//* 按顺序执行以下三步: *///1.创建一个商品hsp_goods表, 选用适当的数据类型//String sql = "create table hsp_goods ( id int, name varchar(32), price double, introduce text)";//2.添加2条数据String sql = "insert into hsp_goods values(1, '华为手机', 2000, '这是不错的一款手机')" ;//3.删除表goods//String sql = "drop table hsp_goods" ;//得到statement对象,把sql语句发送给mysql执行Statement statement = connection.createStatement();statement.executeUpdate(sql);//最后关闭连接statement.close();connection.close();System.out.println("成功~");}
}

02.第二种方法:JDBC( :Java数据库连接)

01.如何通过JDBC连接MySQL(用 DriverManager 类连接数据库)

DriverManager类:用于管理一组 JDBC 驱动程序的基本服务。注意:    javax.sql.DataSource 接口是 JDBC 2.0 API 中的新接口,它提供了另一种连接数据源的方法。调用方法:getConnection(url,user,password):尝试建立到给定数据库 URL 的连接   密码:就是数据库的登录密码root
1、
《首先导入emp数据库》:
导入( *.sql )批处理文件:导入emp数据库:
(1)把老师的emp.zip解压出来得到一个emp.sql文件, 建议把这个文件放到某个盘的根目录 比如 F盘根目录,然后在mysql客户端执行指令:————>格式:  source 路径;  例:  source f:/danei/Java/emp/emp.sql;
(2)在mysql客户端测试以下SQL语句 检查是否成功:show databases; //检查里面是否多了一个empdb;show tables; //会出现两个表 emp 和deptselect * from emp; //检查是否出现了数据,  如果格式错乱  正常
(3)如果出现乱码执行 set names utf8;
(4)在mysql客户端执行sql语句查看是否导入数据库的数据成功。- show databases;- show tables;2、
(1)创建Maven工程
(2)在工程的pom.xml文件中 添加MySQL驱动的依赖坐标(苍老师文档服务器中【配置文件】打开【pom.xml常用配置】中的【MySQL驱动】下的代码复制MySQL驱动的依赖:   )<!-- 连接MySQL数据库的依赖 --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.15</version></dependency>(3)IDEA页面右侧出现maven图标——>点击刷新maven
(4)检查工程目录中 External Libraries 里面 是否出现了  mysql相关的内容
(5)添加《Demo01.java》并在main方法中添加以下代码以在mysql数据库创建jdbct1表格:
package cn.tedu;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
/*** 要求:连接数据库,用java程序创建一个表格** 1.Connection接口:与特定数据库的连接(会话)。在连接的上下文中执行 SQL 语句并返回结果。*                Connection 对象的数据库能够提供描述它的表、它支持的 SQL 语法、它的存储过程、这个连接的能力等等的信息。*                此信息是通过 getMetaData 方法获得的。*   (1)createStatement():创建一个 Statement 对象,用于将 SQL 语句发送到数据库** 2.DriverManager类:用于管理一组 JDBC 驱动程序的基本服务。*                   注意: javax.sql.DataSource 接口是 JDBC 2.0 API 中的新接口,它提供了另一种连接数据源的方法。*   (1)getConnection(url,user,password):尝试建立到给定数据库 URL 的连接   密码:就是数据库的登录密码root** 3.Statement类:用于执行静态 SQL 语句并返回它产生的结果的对象*   (1)execute(String sql):执行给定的 SQL 语句,该语句可能返回多个结果*/
public class Demo01 {public static void main(String[] args) throws SQLException {//1.创建链接对象 异常抛出Connection conn =DriverManager.getConnection("jdbc:mysql://localhost:3306/empdb?characterEncoding=utf8&serverTimezone=Asia/Shanghai","root","root");System.out.println("链接对象:"+conn);//2.创建执行SQL语句的对象Statement s = conn.createStatement();//3.执行SQL语句 execute执行s.execute("create table jdbct1(age int)");//创建一个jdbt1的表//4.关闭资源conn.close();System.out.println("执行完成!");//此时回到mysql客户端 输入命令:【use empdeb;  、 show tables 】发现有了jdbt1这个表格}
}(6)再创建《Demo02.java》,在此文件中删除刚才创建的表格(jdbct1):
只有第三步执行SQL语句不一样: 改为删除表格:【s.execute("drop table jdbct1");】
package cn.tedu.day01;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
/*** 此案例用来:《删除刚才创建的表格(jdbct1)》*/
public class Demo02 {public static void main(String[] args) throws SQLException {//1.创建链接对象Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/empdb?characterEncoding=utf8&serverTimezone=Asia/Shanghai","root","root");System.out.println("链接对象:"+conn);//2.创建执行SQL语句的对象Statement s = conn.createStatement();//3.执行SQL语句的对象(创建一个jdbt1的表)s.execute("drop table jdbc1");//40.关闭资源conn.close();System.out.println("执行完成!");//此时回到mysql客户端 输入命令:【use empdeb;  、 show tables 】发现没有了jdbt1这个表格}
}

(1):

(4):

02.执行SQL语句的对象Statement

execute("sql");
此方法可以执行任意SQL语句, 但建议执行DDL(数据库相关和表相关的SQL语句) int row = executeUpdate("sql");
此方法用来执行增删改【executeUpdate("sql")】相关的SQL语句, 返回值表示生效的行数ResultSet rs = executeQuery(sql);
此方法用来执行查询相关的SQL语句,返回值ResultSet叫做结果集对象,
查询到的数据都装在此对象中

(1)增删改插练习题:

package cn.tedu;
import java.sql.*;
/*** 《本案例用来练习 java 操作数据库进行增删改查的练习》** (1)int executeUpdate(String sql):此方法用来执行增删改【executeUpdate("sql")】相关的SQL语句, 返回值表示生效的行数* (2)execute("sql"):此方法可以执行任意SQL语句, 但建议执行DDL(数据库相关和表相关的SQL语句)** 1、ResultSet类:表示数据库结果集的数据表,通常通过执行查询数据库的语句生成。*                ResultSet 对象维护一个指向其当前数据行的游标。最初,光标位于第一行之前。*                next方法:将光标移动到下一行,并且因为它在ResultSet对象中没有更多行时返回false,*                  所以可以在while循环中使用它来遍历结果集。*   (1)ResultSet rs = executeQuery(sql);*      此方法用来执行查询相关的SQL语句,返回值ResultSet叫做结果集对象,查询到的数据都装在此对象中*/
public class Demo03 {public static void main(String[] args) throws SQLException {//1.创建链接(Connection)对象 有异常抛出Connection conn =DriverManager.getConnection("jdbc:mysql://localhost:3306/empdb?characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false","root","root");//2.创建执行SQL语句的对象Statement s = conn.createStatement();//3.1 执行插入数据SQL
//        s.executeUpdate("insert into emp(name) values('tom')");//在emp表中插入 tom信息//3.2 执行修改的SQL语句:将tom修改为jerry
//        s.executeUpdate("update emp set name='jerry' where name='tom'");//3.3 执行删除的SQL语句s.executeUpdate("delete from emp where name='jerry'");//3.4 执行查询的SQL语句:查询emp表中的名字对应工资ResultSet rs = s.executeQuery("select name,sal from emp;");//(1)遍历 结果集 中的数据在控制台显示:两种方式①②while(rs.next()){//若为true,有下一条数据,则走循环//①获取游标指向的这条数据的某个字段的值,通过字段名获取
//            String name = rs.getString("name");
//            double sal = rs.getDouble("sal");//②通过查询回来的位置获取数据:String name = rs.getString(1);//查询回来的第1个字段double sal = rs.getDouble(2);//查询回来的第2个字段System.out.println(name+":"+sal);}//4.关闭资源conn.close();System.out.println("执行完成!");//3.1 此时回到mysql客户端 输入命令:【use empdb;  show tables;  select * from emp;】发现emp这个表中添加了tom信息//3.2 此时回到mysql客户端 输入命令:【select * from emp;】发现emp这个表中tom换为了"jerry"!//3.3 此时回到mysql客户端 输入命令:【select * from emp;】发现emp这个表中的字段:"jerry"被删除成功!}
}

(2)创建 数据库实用程序:DBUtils类

将 DriverManager 类 调用 getConnection() 方法 连接数据库的代码封装成一个 数据库实用程序:DBUtils 方便调用。
package cn.tedu;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
/*** 数据库实用程序:DBUtils** 此代码实现:将 DriverManager 类 调用 getConnection() 方法 连接数据库的代码封装成一个 数据库实用程序:DBUtils 方便调用。*/
public class DBUtils {public static Connection getConn() throws SQLException {Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/empdb?characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false","root","root");return conn;}
}

(3)用java程序遍历表格的name属性的数据

package cn.tedu.day01;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
/*** 用java程序来遍历数据库中表格的属性name* 以下两种方法都可以*/
public class Demo04_DBUtils {public static void main(String[] args) throws SQLException {/*** 第一种方法:*///从工具类获取链接对象try (Connection conn = DBUtils.getConn()) {//若还是有报错:alt+回车选择:set language...即可//创建执行SQL语句的对象Statement s = conn.createStatement();//执行查询ResultSet rs = s.executeQuery("select name from emp");//遍历 结果集 中的数据在控制台显示:while(rs.next()){//通过查询回来的位置获取数据:String name = rs.getString(1);System.out.println(name);}} catch (SQLException throwables) {throwables.printStackTrace();}/*** 第二种方法:*/
//        //从工具类获取链接对象
//        Connection conn = DBUtils.getConn();//若还是有报错:alt+回车选择:抛出异常即可
//            //创建执行SQL语句的对象
//            Statement s = conn.createStatement();
//            //执行查询
//            ResultSet rs = s.executeQuery("select name from emp");
//            //遍历 结果集 中的数据在控制台显示:
//            while(rs.next()){//                //通过查询回来的位置获取数据:
//                String name = rs.getString(1);
//                System.out.println(name);
//            }/*孙悟空猪八戒沙僧啊唐僧啊刘备啊关羽啊张飞啊观音啊白骨精蜘蛛精黑熊怪灭霸tom*/}
}

(4)创建一个hero表 有id,name,money价格 id自增

package cn.tedu;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class DBUtils {public static Connection getConn() throws SQLException {Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/empdb?characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false","root","root");return conn;}
}package cn.tedu;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
/*** 要求:创建hero表格*      (1)添加main方法,方法中创建一个hero表  有id,name,money价格 id自增*      (2)需要用上DBUtils工具类*/
public class Demo05_DBUtils {public static void main(String[] args) {//从工具类中获取链接对象try (Connection conn  = DBUtils.getConn()){//若还是有报错:alt+回车选择:set language...即可//创建执行SQL语句的对象Statement s = conn.createStatement();s.execute("create table hero"+"(id int primary key auto_increment,name varchar(50),money int)");System.out.println("执行完成!");} catch (SQLException throwables) {throwables.printStackTrace();}}//此时回到mysql客户端 输入命令:【use empdb; show tables; desc hero; 】发现hero表中相关信息
}

(5.1)创建hero表,通过扫描控制台信息存入该表

package cn.tedu;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
/*** 1、DBUtils(数据库实用程序):提供getConnection方法被其他类调用*   (1)getConnection(url,user,password):尝试建立到给定数据库 URL 的连接   密码:就是数据库的登录密码root*/
public class DBUtils {public static Connection getConn() throws SQLException {Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/empdb?characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false","root","root");return conn;}
}package cn.tedu.day01;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Scanner;
/*** 创建hero表,通过扫描仪来扫描控制台输入的信息来存入该表*/
public class Demo06_DBUtils {public static void main(String[] args) {// 创建扫描仪Scanner:Scanner sc = new Scanner(System.in);System.out.println("请输入英雄名");String name = sc.nextLine();System.out.println("请输入价格");int money = sc.nextInt();//获取数据库链接:把得到的英雄名和价格 保存到hero表里try(Connection conn = DBUtils.getConn()) {//创建执行sql语句的对象Statement s = conn.createStatement();//执行插入数据sql语句://因为name是字符串所以加单引号(在java代码中:若造双引号里添加字符串就需要写出:'"xxx"'的样子// money是数字所以不用加单引号直接双引号即可)s.executeUpdate("insert  into hero values(null, '"+name+"' , "+money+")");System.out.println("添加数据成功!");} catch (SQLException throwables) {throwables.printStackTrace();}}//此时回到mysql客户端 输入命令:【use empdb;  、 select * from hero; 】发现hero这个表格存在且在控制台输入的内容可以存进来
}

(5.2)遍历hero的表并在控制台显示

package cn.tedu;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
/*** 1、DBUtils(数据库实用程序):提供getConnection方法被其他类调用*   (1)getConnection(url,user,password):尝试建立到给定数据库 URL 的连接   密码:就是数据库的登录密码root*/
public class DBUtils {public static Connection getConn() throws SQLException {Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/empdb?characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false","root","root");return conn;}
}package cn.tedu;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
/*** 要求:遍历hero的表中的数据并在控制台显示** 1.Connection接口:与特定数据库的连接(会话)。在连接的上下文中执行 SQL 语句并返回结果。*                Connection 对象的数据库能够提供描述它的表、它支持的 SQL 语法、它的存储过程、这个连接的能力等等的信息。*                此信息是通过 getMetaData 方法获得的。*   (1)createStatement():创建一个 Statement 对象,用于将 SQL 语句发送到数据库** 2.ResultSet rs = executeQuery(sql)*   :此方法用来执行查询相关的SQL语句,返回值ResultSet叫做结果集对象,查询到的数据都装在此对象中*/
public class Demo07_DBUtils {public static void main(String[] args) {//把英雄表的所有信息查询出来并在控制台输出:try (Connection conn = DBUtils.getConn()){//创建执行SQL语句的对象:Statement s = conn.createStatement();//执行查询SQL语句:ResultSet r = s.executeQuery("select * from hero");//遍历 结果集 中的数据在控制台显示while(r.next()){int id = r.getInt(1);String name = r.getString(2);int money = r.getInt(3);System.out.println(id+":"+name+":"+money);//此时在控制台即可遍历到hero表中的信息:【1:牛魔王:500】}} catch (SQLException throwables) {throwables.printStackTrace();}}
}

03.数据库连接池DBCP

DataBaseConnectionPool : 数据库连接池作用: 将连接重用,从而提高执行效率

(1)如何使用数据库连接池?

在苍老师网站:配置文件:pom.xml常用下载中的: Druid数据库连接池代码(下面↓)复制粘贴到:
IDEA中:maven下:pom.xml文件中的:添加依赖:<dependencies></dependencies>中,
和<dependency>并列,
点击右侧刷新按钮后,External Libraries下多了一个阿里巴巴的maven文件,成功!<!-- 数据库连接池 -->
<dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.1.21</version>
</dependency>创建 Demo08_DBUtils_Druid:
package cn.tedu;
import com.alibaba.druid.pool.DruidDataSource;
import java.sql.Connection;
import java.sql.SQLException;
/*** 要求:导入数据库连接池依赖并设置数据库连接信息*      :在maven的pom.xml文件中导入阿里巴巴的数据库连接池依赖** (1)getConnection(url,user,password):尝试建立到给定数据库 URL 的连接   密码:就是数据库的登录密码root*/
public class Demo08_DBUtils_Druid {public static void main(String[] args) throws SQLException {//创建连接池对象DruidDataSource ds = new DruidDataSource();//设置数据库连接信息  url 用户名 密码ds.setUrl("jdbc:mysql://localhost:3306/empdb?characterEncoding=utf8&serverTimezone=Asia/Shanghai");ds.setUsername("root");ds.setPassword("root");//设置初始连接数量ds.setInitialSize(3);//设置最大连接数量ds.setMaxActive(5);//从连接池中获取连接  有异常抛出Connection conn = ds.getConnection();System.out.println("连接对象:"+conn);/*控制台输出以下信息则表示连接成功!:十一月 12, 2022 11:31:37 上午 com.alibaba.druid.pool.DruidDataSource info信息: {dataSource-1} inited连接对象:com.mysql.cj.jdbc.ConnectionImpl@3159c4b8*/}
}

(2)改造DBUtils(数据库实用程序)

package cn.tedu;
import com.alibaba.druid.pool.DruidDataSource;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
/*** 《数据库实用程序:DBUtils》* 下面的代码会实现:*  【将 DriverManager 类 调用 getConnection() 方法 连接数据库的代码封装成一个 数据库实用程序:DBUtils 方便调用。】** public class DBUtils {*     public static Connection getConn() throws SQLException {*         Connection conn = DriverManager.getConnection(*                 "jdbc:mysql://localhost:3306/empdb?characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false",*                 "root",*                 "root"*         );*         return conn;*     }* }** ————————————————————————————————————————————————————————————————————————————————————————** 《下面的代码将 改造上边的 DBUtils(数据库实用程序)》:* 1、DBUtils(数据库实用程序):提供getConnection方法被其他类调用*    (1)getConnection(url,user,password):尝试建立到给定数据库 URL 的连接   密码:就是数据库的登录密码root**/
public class DBUtils_Druid {//全局变量ds(斜体):————>为什么加static?  因为在静态块和静态方法中使用该成员变量。private static DruidDataSource ds;static{ //把创建连接池对象放在静态块中:随着类的加载只加载一次//创建连接池对象:ds = new DruidDataSource();//设置数据库连接信息  url 用户名 密码:ds.setUrl("jdbc:mysql://localhost:3306/empdb?characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false");ds.setUsername("root");ds.setPassword("root");//设置初始连接数量ds.setInitialSize(3);//设置最大连接数量ds.setMaxActive(5);}public static Connection getConn() throws SQLException {//从连接池中获取连接  异常抛出Connection conn = ds.getConnection();System.out.println("连接对象:"+conn);return conn;}
}

(3.1)创建用户表并实现注册登录功能(步骤1-5)

《Demo09要求》:——————>【 在数据库中创建user用户表 并实现 注册用户名相关信息的功能(Demo09(1、)】
《Demo10_one要求》:——————>【在 Demo09 的基础上完成 Demo10(2、) 的登录功能,但该Demo10有sql注入危险】
《Demo10_two要求》:——————>【该 Demo10_two(3、) 程序用来解决Demo10_one的sql注入问题】
1.把扫描仪得到的3个信息保存到user表  参考Demo06
package cn.tedu.day02;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Scanner;
/*** 《Demo09要求》:——————>【 在数据库中创建user用户表 并实现 注册用户名相关信息的功能(Demo09(1、)】** 1、把扫描仪得到的3个信息保存到user表 参考Demo06* 步骤:* (1)首先在mysql客户端例:*   ①use empdb;*   ②create table user(id int primary key auto_increment,username varchar(50),password varchar(50),nick varchar(50))charset=utf8;*   ③用户名小猪猪 密码root 昵称root* (2)完成【下面的代码】后,*    .............. ;*    ①用【 desc user;】查看该表添加的内容*     MariaDB [empdb]> desc user;*     +----------+-------------+------+-----+---------+----------------+*     | Field    | Type        | Null | Key | Default | Extra          |*     +----------+-------------+------+-----+---------+----------------+*     | id       | int(11)     | NO   | PRI | NULL    | auto_increment |*     | username | varchar(50) | YES  |     | NULL    |                |*     | password | varchar(50) | YES  |     | NULL    |                |*     | nick     | varchar(50) | YES  |     | NULL    |                |*     +----------+-------------+------+-----+---------+----------------+*    ②再用【select username,password,nick from user;】查看具体添加的用户信息*     MariaDB [empdb]> select username,password,nick from user;*     +----------+----------+------+*     | username | password | nick |*     +----------+----------+------+*     | 小猪猪   | root     | root |*     +----------+----------+------+** 知识点:* 1.执行插入数据SQL语句固定格式:*   s.executeUpdate("insert into hero values(null,  '"+xxx+"'  ,  '"+xxx+"'  ,  '"+xxx+"'  )");** 2.Statement类:用于执行静态 SQL 语句并返回它产生的结果的对象*   (1)execute(String sql):执行给定的 SQL 语句,该语句可能返回多个结果*/
public class Demo09_DBUtils_Druid {public static void main(String[] args) {// 创建扫描仪Scanner sc = new Scanner(System.in);System.out.println("请输入用户名");String username = sc.nextLine();System.out.println("请输入密码");String password = sc.nextLine();System.out.println("请输入昵称");String nick = sc.nextLine();//获取数据库连接:把得到的英雄名和价格 保存到hero表里面try (Connection conn = DBUtils_Druid.getConn()){//创建执行SQL语句的对象:Statement s = conn.createStatement();//执行插入数据SQL语句://固定格式:  s.executeUpdate("insert into hero values(null,  '"+xxx+"'  ,  "+xxx+"  ,  '"+xxx+"'  )");s.executeUpdate("insert into user values(null, '"+username+"','"+password+"','"+nick+"')");System.out.println("执行完成!");} catch (SQLException throwables) {throwables.printStackTrace();}/*控制台输出:请输入用户名小猪猪请输入密码root请输入昵称root十一月 12, 2022 11:53:48 上午 com.alibaba.druid.pool.DruidDataSource info信息: {dataSource-1} inited连接对象:com.mysql.cj.jdbc.ConnectionImpl@5649fd9b执行完成!*/}
}2.完成登录功能(该Demo10有sql注入危险)
package cn.tedu.day02;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Scanner;
/***《Demo10_one要求》:——————>【在 Demo09 的基础上完成 Demo10(2、) 的登录功能,但该Demo10有sql注入危险】** 2、完成登录功能(有sql注入问题)*    步骤:*    (1)完成下面的代码,*       // 运行该程序后,控制台输入之前注册的用户名小猪猪,密码root即可登陆成功!*    (2)再进行【SQL注入【' or '1'='1】:发现登陆成功!】:*       // 运行该程序后,用户名随便输入,然后密码输入【' or '1'='1】测试发现SQL注入成功,可以登录成功!** 知识点:*   ResultSet结果集:表示数据库结果集的数据表,通常通过执行查询数据库的语句生成。*     (1)方法:executeQuery(sql):*     :此方法用来执行查询相关的SQL语句,查询结束后,返回值ResultSet叫做结果集对象,查询到的数据都装在此对象中*     (2)方法:getString(...):*     :意为取得该列的数据以字符串的形式返回*     (3)方法:getString(String c):*     :获取数据库中某个类型(可以是varchar类型)字段值的方法,*     (4)方法:next():*     :ResultSet 对象维护一个指向其当前数据行的游标。最初,光标位于第一行之前。*     next方法:将光标移动到下一行,并且因为它在ResultSet对象中没有更多行时返回false,*     所以可以在while循环中使用它来遍历结果集。**/
public class Demo10_one_DBUtils_Druid {public static void main(String[] args) {//创建扫描仪Scanner sc = new Scanner(System.in);System.out.println("请输入用户名");String username = sc.nextLine();System.out.println("请输入密码");String password = sc.nextLine();//获取连接 判断用户输入的是否正确//获取数据库连接:try(Connection conn = DBUtils_Druid.getConn()){//创建执行SQL语句的对象:Statement s = conn.createStatement();//固定格式:  s.executeUpdate("insert into hero values(null,  '"+xxx+"'  ,  "+xxx+"  ,  '"+xxx+"'  )");ResultSet rs = s.executeQuery("select count(*) from user where username='"+username+"' and password='" +password+"'");//游标往下移动 指向查询回来的数据rs.next();//从结果集对象中取出此时游标指向的数据int count = rs.getInt(1);if(count > 0){System.out.println("登录成功!");}else {System.out.println("用户名或密码错误!");}}catch (SQLException throwables){throwables.printStackTrace();}/*//运行该程序后,控制台输入之前注册的用户名小猪猪,密码root即可登陆成功!控制台显示:请输入用户名小猪猪请输入密码root十一月 14, 2022 10:06:29 上午 com.alibaba.druid.pool.DruidDataSource info信息: {dataSource-1} inited连接对象:com.mysql.cj.jdbc.ConnectionImpl@5649fd9b登录成功!//【进行SQL注入【' or '1'='1】:发现登陆成功!】:// 运行程序后,用户名随便输入,然后密码输入【' or '1'='1】测试发现SQL注入成功,可以登录成功!控制台显示:请输入用户名ferg请输入密码' or '1'='1十一月 14, 2022 10:09:02 上午 com.alibaba.druid.pool.DruidDataSource info信息: {dataSource-1} inited连接对象:com.mysql.cj.jdbc.ConnectionImpl@5649fd9b登录成功!*/}
}3.查询是否有该用户信息
select count(*) from user where username='tom' and password='123456';因为没有添加该用户,所以显示:无
MariaDB [empdb]> select count(*) from user where username='tom' and password='123456';
+----------+
| count(*) |
+----------+
|        0 |
+----------+
1 row in set (0.000 sec)4.查询有几个用户:count(*)select count(*) from user;5.where username='abcd' and password='' or '1'='1'进行SQL注入【' or '1'='1】:发现登陆成功!↓↓↓↓↓↓↓↓↓↓↓控制台显示:请输入用户名ferg请输入密码' or '1'='1十一月 14, 2022 10:09:02 上午 com.alibaba.druid.pool.DruidDataSource info信息: {dataSource-1} inited连接对象:com.mysql.cj.jdbc.ConnectionImpl@5649fd9b登录成功!

(3.2)解决SQL注入问题—>通过PreparedStatement(表示预编译 SQL 语句的对象)

ResultSet结果集:表示数据库结果集的数据表,通常通过执行查询数据库的语句生成。
(1)方法:executeQuery(sql)::此方法用来执行查询相关的SQL语句,查询结束后,返回值ResultSet叫做结果集对象,查询到的数据都装在此对象中
(2)方法:getString(...)::意为取得该列的数据以字符串的形式返回
(3)方法:getString(String c)::获取数据库中某个类型(可以是varchar类型)字段值的方法,
(4)方法:next()::ResultSet 对象维护一个指向其当前数据行的游标。最初,光标位于第一行之前。next方法:将光标移动到下一行,并且因为它在ResultSet对象中没有更多行时返回false,所以可以在while循环中使用它来遍历结果集。
——————————————————————————————————————————————————————————————————————————————————
PreparedStatement:表示预编译 SQL 语句的对象。 SQL 语句被预编译并存储在 PreparedStatement 对象中。然后可以使用该对象多次有效地执行该语句
(1)PreparedStatement对象可以将编译SQL语句的时间点提前,提前后可以将SQL语句逻辑部分提前锁死, 用户输入的内容将不能影响原有SQL语句的逻辑部分,从而解决了SQL注入的问题
(2)如果SQL语句中《存在》变量,则必须使用PreparedStatement,解决SQL注入问题, 而且可以提高开发效率(避免了拼接字符串) 。
(3)如果SQL语句中《没有》变量,可以使用Statement或PreparedStatement
(4)方法:prepareStatement(String sql)::创建一个 PreparedStatement 对象,用于将参数化的 SQL 语句发送到数据库。带或不带 IN 参数的 SQL 语句可以预编译并存储在 PreparedStatement 对象中。然后可以使用该对象多次有效地执行该语句。
(5)总结:通过PreparedStatement可以避免出现SQL注入往传递值的地方传递进来了SQL语句,导致原有SQL语句逻辑改变
——————————————————————————————————————————————————————————————————————————————————
改造Demo10后的代码,成功解决sql注入问题:
package cn.tedu.day02;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Scanner;
/***《Demo10_two要求》:——————>【该 Demo10_two(3、) 程序用来解决Demo10_one的sql注入问题】** 3、完成登录功能(解决sql注入问题)*    步骤:*    (1)完成下面的代码,*       //运行该程序后,控制台输入之前注册的用户名小猪猪,密码root即可登陆成功!*       //运行该程序后,用户名随便输入,然后密码输入【' or '1'='1】测试发现SQL注入已经解决成功,不可以登录!** 知识点:*   ResultSet结果集:表示数据库结果集的数据表,通常通过执行查询数据库的语句生成。*     (1)方法:executeQuery(sql):*             :此方法用来执行查询相关的SQL语句,查询结束后,返回值ResultSet叫做结果集对象,查询到的数据都装在此对象中*     (2)方法:getString(...):*             :意为取得该列的数据以字符串的形式返回*     (3)方法:getString(String c):*             :获取数据库中某个类型(可以是varchar类型)字段值的方法,*     (4)方法:next():*             :ResultSet 对象维护一个指向其当前数据行的游标。最初,光标位于第一行之前。*               next方法:将光标移动到下一行,并且因为它在ResultSet对象中没有更多行时返回false,*                         所以可以在while循环中使用它来遍历结果集。**   PreparedStatement:表示预编译 SQL 语句的对象。*                        SQL 语句被预编译并存储在 PreparedStatement 对象中。*                       然后可以使用该对象多次有效地执行该语句*    (1)PreparedStatement对象可以将编译SQL语句的时间点提前,*       提前后可以将SQL语句逻辑部分提前锁死,*       用户输入的内容将不能影响原有SQL语句的逻辑部分,从而解决了SQL注入的问题*    (2)如果SQL语句中《存在》变量,则必须使用PreparedStatement,解决SQL注入问题,*       而且可以提高开发效率(避免了拼接字符串) 。*    (3)如果SQL语句中《没有》变量,可以使用Statement或PreparedStatement*    (4)方法:prepareStatement(String sql):*             :创建一个 PreparedStatement 对象,用于将参数化的 SQL 语句发送到数据库。*               带或不带 IN 参数的 SQL 语句可以预编译并存储在 PreparedStatement 对象中。*               然后可以使用该对象多次有效地执行该语句。*    (5)总结:通过PreparedStatement可以避免出现SQL注入*         往传递值的地方传递进来了SQL语句,导致原有SQL语句逻辑改变*/
public class Demo10_two_DBUtils_Druid {public static void main(String[] args) {//创建一个扫描仪:Scanner sc = new Scanner(System.in);System.out.println("请输入用户名");String username = sc.nextLine();System.out.println("请输入密码");String password = sc.nextLine();//获取连接 判断用户输入的是否正确//获取数据库连接:try(Connection conn = DBUtils_Druid.getConn()){//通过PreparedStatement 解决SQL注入问题String sql = "select count(*) from user where username=? and password=?";//编译SQL语句的时间点从之前执行时,提前到了创建对象时,好处是此时编译用户输入的内容// -还不在SQL语句里面,只是将原有SQL语句进行编译,此时可以将原有SQL语句的逻辑部分锁死PreparedStatement ps = conn.prepareStatement(sql);//把?替换成变量1和2代表?的位置  此时替换时只能以值的形式添加到原有SQL语句中,因为// -逻辑部分已经编译好 已经锁死,这样用户输入的内容则不会影响原有SQL语句的逻辑。ps.setString(1,username);ps.setString(2,password);ResultSet rs = ps.executeQuery();//游标往下移动 指向查询回来的数据rs.next();//从结果集对象中取出此时游标指向的数据int count = rs.getInt(1);if(count > 0){System.out.println("登录成功!");}else {System.out.println("用户名或密码错误!");}} catch (SQLException throwables) {throwables.printStackTrace();}}/*//运行该程序后,控制台输入之前注册的用户名小猪猪,密码root即可登陆成功!控制台显示:请输入用户名小猪猪请输入密码root十一月 14, 2022 10:48:54 上午 com.alibaba.druid.pool.DruidDataSource info信息: {dataSource-1} inited连接对象:com.mysql.cj.jdbc.ConnectionImpl@5649fd9b登录成功!//【进行SQL注入【' or '1'='1】:发现不可以登录!】:// 运行程序后,用户名随便输入,然后密码输入【' or '1'='1】测试发现SQL注入已经解决成功,不可以登录!控制台显示:请输入用户名ferg请输入密码' or '1'='1十一月 14, 2022 10:50:10 上午 com.alibaba.druid.pool.DruidDataSource info信息: {dataSource-1} inited连接对象:com.mysql.cj.jdbc.ConnectionImpl@5649fd9b用户名或密码错误!*/
}

(4.1)实现验证用户名密码登录更清楚的提示功能

package cn.tedu.day02;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Scanner;
/*** 实现验证用户名密码登录更清楚的提示功能*/
public class Demo11_DBUtils_Druid {public static void main(String[] args) {//创建一个扫描仪:Scanner sc = new Scanner(System.in);System.out.println("请输入用户名");String username = sc.nextLine();System.out.println("请输入密码");String password = sc.nextLine();//获取连接 判断用户输入的是否正确//获取数据库连接:try (Connection conn = DBUtils_Druid.getConn()){//通过PreparedStatement 解决SQL注入问题String sql = "select password from user where username=?";//编译SQL语句的时间点从之前执行时,提前到了创建对象时,好处是此时编译用户输入的内容// -还不在SQL语句里面,只是将原有SQL语句进行编译,此时可以将原有SQL语句的逻辑部分锁死PreparedStatement ps = conn.prepareStatement(sql);//把?替换成变量1和2代表?的位置  此时替换时只能以值的形式添加到原有SQL语句中,因为// -逻辑部分已经编译好 已经锁死,这样用户输入的内容则不会影响原有SQL语句的逻辑。ps.setString(1,username);//1:代表的第一个“?”问号//执行查询ResultSet rs = ps.executeQuery();//判断是否有数据if(rs.next()){//得到查询到的密码String pw = rs.getString(1);//代表查询的第一个字段//拿用户输入的密码和查询到的密码比较if(pw.equals(password)){System.out.println("登陆成功");}else{System.out.println("密码错误");}}else{System.out.println("用户名不存在!");}} catch (SQLException throwables) {throwables.printStackTrace();}}
}

(4.2)使用PreparedStatement实现注册功能(并实现用户名不能重复的功能)

package cn.tedu.day02;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Scanner;
/*** 要求:使用PreparedStatement实现注册功能  并实现用户名不能重复的功能*/
public class Demo12_DBUtils_Druid {public static void main(String[] args) {//创建一个扫描仪:Scanner sc = new Scanner(System.in);System.out.println("请输入用户名");String username = sc.nextLine();System.out.println("请输入密码");String password = sc.nextLine();System.out.println("请输入昵称");String nick = sc.nextLine();//获取连接 判断用户输入的是否正确//获取数据库连接:try (Connection conn = DBUtils_Druid.getConn()){/*** 使用PreparedStatement(可以避免SQL注入问题)实现注册功能  并实现用户名不能重复的功能*///1.查询用户名是否存在:String sql = "select password from user where username=?";//编译SQL语句的时间点从之前执行时,提前到了创建对象时,好处是此时编译用户输入的内容// -还不在SQL语句里面,只是将原有SQL语句进行编译,此时可以将原有SQL语句的逻辑部分锁死PreparedStatement ps = conn.prepareStatement(sql);//把?替换成变量1和2代表?的位置  此时替换时只能以值的形式添加到原有SQL语句中,因为// -逻辑部分已经编译好 已经锁死,这样用户输入的内容则不会影响原有SQL语句的逻辑。ps.setString(1,username);//1:代表的第一个“?”问号//执行查询ResultSet rs = ps.executeQuery();//判断是否有数据if(rs.next()){System.out.println("用户名已存在");return;}//2.实现往user表中添加数据:String insertSql = "insert into user values(null,?,?,?)";PreparedStatement insertPs = conn.prepareStatement(insertSql);insertPs.setString(1,username);insertPs.setString(2,password);insertPs.setString(3,nick);//执行插入insertPs.executeUpdate();System.out.println("注册完成!");} catch (SQLException throwables) {throwables.printStackTrace();}}/*(1)测试输入 重复 的用户名会 提示用户名用户名已存在:请输入用户名小猪猪请输入密码哈请输入昵称哈十一月 14, 2022 11:22:45 上午 com.alibaba.druid.pool.DruidDataSource info信息: {dataSource-1} inited连接对象:com.mysql.cj.jdbc.ConnectionImpl@5649fd9b用户名已存在(2)测试输入 不重复 的用户名会 注册成功:请输入用户名猪猪侠请输入密码root请输入昵称猪猪侠十一月 14, 2022 11:23:45 上午 com.alibaba.druid.pool.DruidDataSource info信息: {dataSource-1} inited连接对象:com.mysql.cj.jdbc.ConnectionImpl@5649fd9b注册完成!    */
}

————————————————

二、SQL操作语句

1、库操作:

00.常见指令

#注释的快捷键 shift+ctrl+c , 注销注释 shift+ctrl+r# 演示数据库的操作
#创建一个名称为hsp_db01的数据库。[图形化和指令 演示]# 查看数据库
show databases;
#(1)创建数据库
CREATE DATABASE hsp_db01;
#(2)创建数据库(若不存在则创建):create database if not exits
create database if not exists hsp_db01 default charset utf8mb4;
#(3)在创建数据库,表的时候,为了规避关键字(若创建的数据库名字是关键字可能创建不成功,则可以加反引号:``来成功创建),可以使用反引号解决;注意删除的时候也需要用反引号
create database `CREATE`
# 修改数据库参数
alter database hsp_db01 charset utf8;
show create database hsp_db01;
alter database hsp_db01 charset utf8mb4;
show create database hsp_db01;
# 删除数据库指令————>慎用!!!
DROP DATABASE hsp_db01;
————————————————————————————————————————————————————————————
#创建数据库
CREATE DATABASE hsp_db01;# 查看前面创建的 hsp_db01 数据库的定义信息
show create database hsp_db01;# 进入hsp_db01数据库
use hsp_db01;#创建一个使用utf8字符集的hsp_db02数据库,默认不区分大小写# mysql 的:utf8是三个字节的阉割版utf8编码#          utf8mb4 是完整的utf8编码
CREATE DATABASE hsp_db02 CHARACTER SET utf8;
#进入hsp_db02数据库
use hsp_db02;
#创建t1表格
create table t1(id int,name varchar(20));
#插入TOM 和 tom两条数据
insert into t1 values (1,'Tom'),(2,'tom');#创建一个使用utf8字符集,并带校对规则(COLLATE)区分大小写的hsp_db03数据库
#注:【校对规则(COLLATE): utf8_bin:区分大小 默认utf8_general_ci:不区分大小写】
CREATE DATABASE hsp_db03 CHARACTER SET utf8 COLLATE utf8_bin;
#进入hsp_db03数据库
use hsp_db03;
#创建t1表格
create table t1(id int,name varchar(20));
#插入TOM 和 tom两条数据
insert into t1 valu3es (1,'Tom'),(2,'tom');——  ——  ——  ——  ——  ——  ——  ——  ——  ——  ——  ——  ——  ——  ——  ——  ——  #例题:根据创建数据库时是否添加校验规则来验证是否查询结果为不同的数据
(0)下面是一条查询的sql:
SELECT *  FROM t1 WHERE NAME = 'tom';上面sql语句翻译:
select(查询) *(表示所有字段) FROM t1(从哪个表) WHERE(从哪个字段) NAME = 'tom'(查询名字是tom)(1)由于上面我们在hsp_db02数据库中没写校对规则,则是默认的。不会区分大小写。因此使用(0)中的sql查询结果 会显示两条数据:查询显示:id   name1    Tom2    tom(2)由于上面我们在hsp_db03数据库中写了校对规则utf8_bin会区分大小写,因此使用(0)中的sql查询结果会 只显示1条数据:查询显示:id   name1    tom
————————————————————————————————————————————————————————————————
注:《关于utf8mb4》
在现行的MySQL版本中,如果使用utf8编码,表示的是utf8mb3,
将最多使用3个字节来表示1个字符,而utf8mb4将最多使用4个字节表示1个字符。
使用utf8mb4将有更多的可能性,例如可以表示一些生僻字,emojo表情等,
同时,由于是“最多”使用4字节,如果某个字符只需要3字节即可表示,也只会使用3字节,
并不会造成存储空间的浪费,所以,通常建议将各数据表的编码显式的指定为utf8mb4。

01.备份/恢复数据库

《备份数据库》:(1)
在dos窗口的该路径:【D:\soft\xxx\MariaDB\danei\bin>】
下执行备份数据库【mysqldump】命令:
——>【mysqldump -u root -p -B hsp  > d:\d.sql】mysqldump -u 用户名 -p -B 数据库1 数据库2 数据库n > 保存的路径名:\文件名(2)
敲回车后,dos窗口中会返回:【Enter password: 】,(3)
输入密码【root】——>敲回车(4)
观察该d盘路径,已经有了【d.sql】文件
————————————————————————————————————————————————
《恢复数据库》:1、第一种恢复的方法:
(0)将上面备份好的数据库 hsp 删除:【DROP DATABASE hsp;】然后执行下面的恢复命令:
(1)进入mysql客户端的命令行再执行:【mysql -u root -p  回车,输入密码】再执行
(2)输入指令:【source d:\\d.sql】 敲回车
(3)发现刚才被删的数据库又回来了。2、第2种恢复的方法:
(0)将上面备份好的数据库 hsp 删除:【DROP DATABASE hsp;】然后执行下面的恢复命令:
(1将备份的数据库“.sql”文件中的内容全部复制下来,再从SQLyog数据库可视化工具里打开,再打开一个编辑sql语句的窗口,将复制的“.sql”文件的内容全部执行即可

2、表操作

00.表中列名的常用数据类型有哪些


(1)列类型——数值型(整数int bigint/浮点数double)

整数: int(m)和bigint(m)       m代表显示长度,   m=5   存18  查询得到00018
create table t3(age int(5) zerofill);
insert into t3 values(18);
select * from t3;浮点数: double(m,d)  m代表总长度,d代表小数长度 ,   存23.212    m=5    d=3
create table t5(price double(5,3));
insert into t5 values(23.32123);
insert into t5 values(233.32123);  //报错
【演示 bit 类型使用】:#1.bit(m)  m范围:1~64
#2.添加数据范围按照给定的位(bit)数来确定,比如 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;
———————————————————————————————————————————————————————————————
【演示 tinyint 型的范围】:————>在 tinyint 后添加"unsinged"可以指定有/无符号  说明: 表的字符集,校验规则, 存储引擎,使用默认注意: 【Mysql版本不同,可能导致无法使用该单词来指定。】#1. 如果没指定 unsinged , 则TINYINT就是有符号,范围是 -128 ~ 127#2. 如果  指定 unsinged , 则TINYINT就是无符号 0-255
例:
①如何定义一个有符号的整数
create table t10(id tinyint);//默认是有符号的
INSERT INTO t3 VALUES(127); #这是非常简单的添加语句
SELECT * FROM t3
②如何定义一个无符号的整数
create table t10(id tinyint unsinged);//添加了unsinged是无符号的
INSERT INTO t4 VALUES(255);
SELECT * FROM t4;
———————————————————————————————————————————————————————————————
【演示 BIGINT UNSIGNED 使用】:例:
CREATE TABLE t08(num BIGINT UNSIGNED);
INSERT INTO t08 VALUES(8999999933338388388383838838383009338388383838383838383);
SELECT * FROM t08;
———————————————————————————————————————————————————————————————
【演示 小数型:float/double/decimal 使用】:————>float:单精度double:双精度decimal:可以存放很大的数 【  decimal[M,D] [unsigned]  】
#说明:
#①可以支持更加精确的小数位,M是小数位数(精度)的总数,D是小数点(标度)后面的位数。
#②如果D是0,则值没有小数点或分数部分。M最大65。D最大是30。如果D被省略,默认是0。如果M被省略,默认是10。
#③建议:若希望小数的精度高,推荐使用decimal 例1:
#1.创建表
CREATE TABLE t (num1 FLOAT,num2 DOUBLE,num3 DECIMAL(30,20)
);
#2.添加数据
INSERT INTO t VALUES(88.12345678912345, 88.12345678912345,88.12345678912345
);
#3.查询表格
SELECT * FROM t;
+---------+-------------------+-------------------------+
| num1    | num2              | num3                    |
+---------+-------------------+-------------------------+
| 88.1235 | 88.12345678912345 | 88.12345678912345000000 |
+---------+-------------------+-------------------------+例2:
#decimal可以存放很大的数
CREATE TABLE t07 (num DECIMAL(65));
INSERT INTO t07 VALUES(8999999933338388388383838838383009338388383838383838383);
SELECT * FROM t07;

(2)列类型——文本字符串(char/varchar/text)

《字符串》:
char(m):    固定长度, m=10 存abc  占10, 执行效率略高, 当保存数据的长度相对固定时使用, 最大值255varchar(m): 可变长度,m=10 存abc 占3,更节省空间,最大值65535 但推荐保存短的数据(255以内)text(m):    可变长度, 最大值65535,建议保存长度大于255的
《char 和 varchar的区别》:
1、CHAR的长度是不可变的,而VARCHAR的长度是可变的,也就是说,定义一个CHAR[10]和VARCHAR[10],如果存进去的是‘ABCD’, 那么CHAR所占的长度依然为10,除了字符‘ABCD’外,后面跟六个空格,而VARCHAR的长度变为4了,取数据的时候,CHAR类型的要用trim()去掉多余的空格,而VARCHAR类型是不需要的。
2、CHAR的存取速度要比VARCHAR快得多,因为其长度固定,方便程序的存储与查找;但是CHAR为此付出的是空间的代价,因为其长度固定,所以难免会有多余的空格占位符占据空间,可以说是以空间换取时间效率,而VARCHAR则是以空间效率为首位的。
3、CHAR的存储方式是,一个英文字符(ASCII)占用1个字节,一个汉字占用两个字节;而VARCHAR的存储方式是,一个英文字符占用2个字节,一个汉字也占用2个字节。
4、两者的存储数据都是非unicode的字符数据。
————————————————————————————————————————————————
《分别什么时候使用?》
————>若数据是定长,推荐使用char,比如md5的密码,邮编,手机号,身份证号码等。
————>若一个字段的长度是不确定,使用varchar,比如留言,文章。———————————————————————————————————————————————————————————————
———————————————————————————————————————————————————————————————
【演示 字符串:char varchar 使用】:————>char(size):    固定长度字符串 最大255字符varchar(size): 可变长度字符串 最大65532字节 范围0~65535[utf8编码最大21844字符 1-3个字节用于记录大小]
-- 如果表的编码是 utf8 varchar(size) size = (65535-3) / 3 = 21844
-- 如果表的编码是 gbk  varchar(size) size = (65535-3) / 2 = 32766
例:
CREATE TABLE t09 (`name` CHAR(255));
CREATE TABLE t10 (`name` VARCHAR(21844)) CHARSET utf8;
CREATE TABLE t11 (`name` VARCHAR(32766)) CHARSET gbk;
———————————————————————————————————————————————————————————————
【演示 字符串使用细节】:
#char(4) 和 varchar(4) 这个4表示的是字符,而不是字节, 不区分字符是汉字还是字母
例:
CREATE TABLE t11(`name` CHAR(4));
INSERT INTO t11 VALUES('韩顺平好');
SELECT * FROM t11;
+----------+
| name     |
+----------+
| 韩顺平好 |
+----------+CREATE TABLE t12(`name` VARCHAR(4));
INSERT INTO t12 VALUES('韩顺平好');
INSERT INTO t12 VALUES('ab北京');
SELECT * FROM t12;
+----------+
| name     |
+----------+
| 韩顺平好 |
+----------+#如果varchar不够用想存更多的字符,可选mediumtext 0~2^24 或者longtext 0~2^32
#如果想简单点,可以使用直接使用text(可以将test列视为varchar列,但不能有默认值,大小0~2^16字节)
例:
CREATE TABLE t13( content TEXT, content2 MEDIUMTEXT , content3 LONGTEXT
);
INSERT INTO t13 VALUES('韩顺平教育', '韩顺平教育100', '韩顺平教育1000~~');
SELECT * FROM t13;
+------------+---------------+------------------+
| content    | content2      | content3         |
+------------+---------------+------------------+
| 韩顺平教育 | 韩顺平教育100 | 韩顺平教育1000~~ |
+------------+---------------+------------------+

(3)时间相关的类型:date/time/datetime/timestamp

date: 只能保存年月日
time: 只能保存时分秒
datetime: 保存年月日时分秒, 默认值为null , 最大值 9999-12-31
timestamp:(时间戳,距离1970年1月1日的毫秒数),保存年月日时分秒,默认值为当前系统时间最大值 2038-1-19   例:
create table t6(t1 date,t2 time,t3 datetime,t4 timestamp);
insert into t6 values("2022-5-15",null,null,null);
insert into t6 values(null,"14:20:25","2011-10-22 10:20:30",null);
【演示时间相关的类型】:#1.创建一张表, 列名类型为:date , datetime , timestamp
CREATE TABLE t14 (birthday DATE , -- 生日job_time DATETIME, -- 记录年月日 时分秒login_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP -- 登录时间, 如果希望login_time列自动更新, 需要配置
);
#2.插入生日和日期时间
INSERT INTO t14(birthday, job_time) VALUES('2022-11-11','2022-11-11 10:10:10');
#3.查询该表的数据
SELECT * FROM t14;
+------------+---------------------+---------------------+
| birthday   | job_time            | login_time          |
+------------+---------------------+---------------------+
| 2022-11-11 | 2022-11-11 10:10:10 | 2022-09-01 11:17:50 |
| 2022-11-11 | 2022-11-11 10:10:10 | 2022-09-01 11:18:59 |
+------------+---------------------+---------------------+
-- 如果我们更新 t14表的某条记录,login_time列会自动的以当前时间进行更新

01.1.备份数据库中的表:

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

01.2.如何实现表的复制:

1、《新表存在时》:01.两个表的结构一样【 INSERT INTO 新表 SELECT * FROM 旧表; 】
02.两个表的结构不一样【 INSERT INTO 新表 (字段1,字段2,...) SELECT 字段1,字段2,... FROM 旧表; 】
——————————————————————————————————————————————————————————————————————————————
2、《新表不存在时》:01.复制表结构和数据到新表 /* MYSQL不适用 */【SELECT * INTO 新表 FROM 旧表;】
02. 只复制表结构到新表(1)方法一、【 CREATE TABLE 新表 SELECT * FROM 旧表 WHERE 1=2; /* 即:让WHERE条件不成立 */ 】(2)方法二、【 CREATE TABLE 新表 LIKE 旧表; 】/* CREAT TABLE LIKE 产生与源表相同的表结构,包括索引和主键,数据需要用INSERT INTO 语句复制进去 */
03.只复制数据到新表(1)复制全部数据(新表和旧表相同)【 CERETE TABLE 新表 SELECT * FROM 旧表; 】/* 这种方法会将旧表中所有的内容都拷贝过来,用这种方法需要注意,新表中没有了旧表中的primary key,Extra,auto_increment等属性 */(2)复制某几列数据(新表列数可以多于或者小于旧表列数)【 CREAT TABLE 新表 AS SELECT 字段1,字段2,... FROM 旧表; 】/* CREAT TABLE AS 只是复制原数据,其实就是把查询的结果建一个表 */
《练习题》:-- 一、准备旧表与新表(在同一个数据库中即可)
-- 旧表emp(员工表)的数据:
DROP TABLE IF EXISTS emp;
CREATE TABLE emp(empno  MEDIUMINT UNSIGNED  NOT NULL  DEFAULT 0, /*编号*/ename VARCHAR(20) NOT NULL DEFAULT "", /*名字*/job VARCHAR(9) NOT NULL DEFAULT "",/*工作*/mgr MEDIUMINT UNSIGNED ,/*上级编号*/hiredate DATE NOT NULL,/*入职时间*/sal DECIMAL(7,2)  NOT NULL,/*薪水*/comm DECIMAL(7,2) ,/*红利 奖金*/deptno MEDIUMINT UNSIGNED NOT NULL DEFAULT 0 /*部门编号*/
);
-- 添加测试数据
INSERT INTO emp VALUES
(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);-- 创建新表table1(此时新表已存在)
DROP TABLE IF EXISTS table1;
CREATE TABLE table1(id INT,`name` VARCHAR(32),sal DOUBLE,job VARCHAR(32),deptno INT);
DESC table1;
SELECT * FROM table1;
-- ——————————————————————————————————————————————————————————————————————-- 二、演示如何自我复制(在同一个数据库中操作):-- 1.先把旧表emp 的记录复制到 新表table1 【两个表的结构不一样】INSERT INTO table1(id, `name`, sal, job,deptno) SELECT empno, ename, sal, job, deptno FROM emp;  SELECT * FROM table1;-- 2.自我复制 【 就是新表存在时,两个表的结构一样进行复制 】INSERT INTO table1 SELECT * FROM table1;SELECT COUNT(*) FROM table1;-- 如何删除掉一张表重复记录
-- 1. 先创建一张表 table2
-- 2. 让 table2 有重复的记录-- 【复制表结构:把emp表的结构(列),复制到table2】CREATE TABLE table2 LIKE emp; DESC table2;INSERT INTO table2 SELECT * FROM emp;SELECT * FROM table2;-- 3. 考虑去重 table2的记录
/*思路 (1) 先创建一张临时表 my_tmp , 该表的结构和 table2一样(2) 把my_tmp 的记录 通过 distinct 关键字 处理后 把记录复制到 my_tmp(3) 清除掉 table2 记录(4) 把 my_tmp 表的记录复制到 table2(5) drop 掉 临时表my_tmp*/
-- (1) 先创建一张临时表 my_tmp , 该表的结构和 table2一样【新表不存在时,只复制结构到新表:CREATE TABLE 新表 LIKE 旧表;】CREATE TABLE my_tmp LIKE table2;
-- (2) 把my_tmp 的记录 通过 distinct 关键字 处理后 把记录复制到 my_tmpINSERT INTO my_tmp SELECT DISTINCT * FROM table2;
-- (3) 清除掉 table2 记录DELETE FROM table2;
-- (4) 把 my_tmp 表的记录复制到 table2INSERT INTO table2 SELECT * FROM my_tmp;
-- (5) drop 掉 临时表my_tmpDROP TABLE my_tmp;SELECT * FROM table2;

02.常用指令(创增查改删)

(0)创建emp表

00.《创建emp表》:#创建表时,要根据需保存的数据创建相应的列,并根据数据的类型定义相应的列类型。
-- 字段   属性
-- Id   整形
-- name 字符型
-- sex  性别:字符型
-- brithday   日期型(date)
-- entry_date 日期型 (date)
-- job     工作:字符型
-- Salary  工资:小数型
-- resume  描述:文本型
例:
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;

(1)插入数据:insert

01.《插入表数据》:#第一种方式:
INSERT INTO `emp`VALUES(100, '小妖怪', '男', '2000-11-11', '2010-11-10 11:11:11', '巡山的', 3000, '大王叫我来巡山');#第二种方式:
INSERT INTO `emp`(id, `name`, sex, brithday, entry_date, job, salary,`resume`
)VALUES(100, '小妖怪', '男', '2000-11-11', '2010-11-10 11:11:11', '巡山的', 3000, '大王叫我来巡山');

(2)查的操作:select

02.《查询表数据》:(1)查询表的数据
SELECT * FROM `emp`;+------+--------+------+------------+---------------------+--------+--
|id| name |sex| brithday | entry_date           | job    | salary |
+------+--------+------+------------+---------------------+--------+--
|100|小妖怪| 男 |2000-11-11 | 2010-11-10 11:11:11 | 巡山的 | 3000   |
+------+--------+------+------------+---------------------+--------+--+--------------+
| resume       |
+------+-------+
| 大王叫我来巡山 |
+------+-------+
——————————————————————————————————————————————————————————
(2)查询表的结构(可以查看表的所有列)
【desc 表名;】

(3)改的操作:alter

03.《改变 表中数据 和 表名》:(1)添加列:
格式:【alter table 表名 add 列名 列名数据类型 默认值非空;】需求:员工表emp的上增加一个image列,varchar类型(要求在resume后面)。
例:
ALTER TABLE emp ADD image VARCHAR(32) NOT NULL DEFAULT '' AFTER RESUME;
——————————————————————————————————————————————————————————
(2)修改列名的数据类型:
格式:【alter table 表名 modify 要修改的列名 该列名的数据类型 默认值非空;】需求:修改job列,使其长度为60。
例:
alter table emp modify job varchar(60) not null default '';
——————————————————————————————————————————————————————————
(3)删除列:
格式:【alter table 表名 drop 列名】需求:删除sex列。
例:
ALTER TABLE emp DROP sex;
——————————————————————————————————————————————————————————
(4.1)改表名
格式:【rename table 原表名 to 新表名;】需求:表名改为em。
例:
RENAME TABLE emp TO em;
——  ——  ——  ——  ——  ——  ——  ——  ——  ——  ——  ——  ——  ——  ——
(4.2)改表中的列名
格式:【alter table 表名 change column 原列名 改后的列名 列名数据类型 默认非空值;】需求:列名name修改为user_name,再改回来
例:
alter table em change column name user_name varchar(64) not null default '';alter table em change column user_name name varchar(64) not null default '';
——————————————————————————————————————————————————————————
(5)修改表的字符集
格式:【alter table 表名 character set 改动后的字符集名称】需求:修改表的字符集为utf8
例:
ALTER TABLE em CHARACTER SET utf8;

03.表设计之:权限管理

任何网站中只要是存在权限管理的需求,表格都是设计成5张表,其中:
三张主表:用户表             两张关系表:用户-角色 关系表  角色表                       角色-权限 关系表权限表1、
(1)创建三张主表
create database lastdb charset=utf8;   //创建数据库use lastdb;
create table user(id int primary key auto_increment,name varchar(50))charset=utf8;
create table role(id int primary key auto_increment,name varchar(50))charset=utf8;
create table module(id int primary key auto_increment,name varchar(50))charset=utf8;(2)创建两张关系表
用户角色关系表:  create table u_r(uid int,rid int);
角色权限关系表:  create table r_m(rid int,mid int);(3)准备数据
insert into user values(null,'刘德华'),(null,'王菲');
insert into role values(null,'男游客'),(null,'女会员');
insert into module values(null,'男浏览'),(null,'男发帖'),(null,'女浏览'),(null,'女发帖');(4)建立关系
刘德华——>男游客和女会员      王菲————>女会员
男游客——>男浏览              女会员——>女浏览,女发帖
例:
刘德华第一个添加进去的,
男游客第一个添加进去的
————>所以下面第一行第一个values后边的对应关系是:(1,1) insert into u_r values(1,1),(1,2),(2,2);insert into r_m values(1,1),(2,3),(2,4);

(1)权限管理关联查询相关练习题

use lastdb;1.查询刘德华有哪些角色?
select r.name
from user u join u_r ur on u.id=ur.uid
join role r on r.id=ur.rid where u.name="刘德华";MariaDB [lastdb]> select r.name-> from user u join u_r ur on u.id=ur.uid-> join role r on r.id=ur.rid where u.name="刘德华";
+--------+
| name   |
+--------+
| 男游客 |
| 女会员 |
+--------+2.查询女会员这个角色对应的用户都有谁?
select u.name
from user u join u_r ur on u.id=ur.uid
join role r on r.id=ur.rid where r.name="女会员";MariaDB [lastdb]> select u.name-> from user u join u_r ur on u.id=ur.uid-> join role r on r.id=ur.rid where r.name="女会员";
+--------+
| name   |
+--------+
| 刘德华 |
| 王菲   |
+--------+3.查询男游客这个角色拥有什么权限?
select m.name
from role r join r_m rm on r.id=rm.rid
join module m on rm.mid=m.id where r.name="男游客";MariaDB [lastdb]> select m.name-> from role r join r_m rm on r.id=rm.rid join module m on rm.mid=m.id where r.name="男游客";
+--------+
| name   |
+--------+
| 男浏览 |
+--------+4.查询女会员这个角色拥有什么权限?
select m.name
from role r join r_m rm on r.id=rm.rid
join module m on rm.mid=m.id where r.name="女会员";MariaDB [lastdb]> select m.name-> from role r join r_m rm on r.id=rm.rid-> join module m on rm.mid=m.id where r.name="女会员";
+--------+
| name   |
+--------+
| 女浏览 |
| 女发帖 |
+--------+5.查询刘德华这个用户拥有什么权限?
select m.name
from user u join u_r ur on u.id=ur.uid
join r_m rm on ur.rid=rm.rid
join module m on m.id=rm.mid
where u.name="刘德华";MariaDB [lastdb]> select m.name-> from user u join u_r ur on u.id=ur.uid-> join r_m rm on ur.rid=rm.rid-> join module m on m.id=rm.mid-> where u.name="刘德华";
+--------+
| name   |
+--------+
| 男浏览 |
| 女浏览 |
| 女发帖 |
+--------+6.查询拥有女发帖这个权限的用户都有谁?
select u.name
from user u join u_r ur on u.id=ur.uid
join r_m rm on ur.rid=rm.rid
join module m on m.id=rm.mid
where m.name="女发帖";MariaDB [lastdb]> select u.name-> from user u join u_r ur on u.id=ur.uid-> join r_m rm on ur.rid=rm.rid-> join module m on m.id=rm.mid-> where m.name="女发帖";
+--------+
| name   |
+--------+
| 刘德华 |
| 王菲   |
+--------+

3、数据库CURD语句

CURD:即增删改查语句
C[create]
R[read  ]————>读取数据,即查询数据
U[update]————>更新数据
D[delete]————>删除数据《使用数据库》:执行表相关和数据相关的SQL语句之前必须先使用了某个数据库
格式: 【use 数据库名;】

01.insert 语句

01.《使用INSERT语句向表中插入数据》。(1)创建一张商品表goods (id  int , goods_name varchar(10), price double );
(2)添加2条记录
CREATE TABLE `goods` (id INT ,goods_name VARCHAR(10), -- 长度10price DOUBLE NOT NULL DEFAULT 100
);
(3)添加数据
INSERT INTO `goods` VALUES(10, '华为手机', 2000);
INSERT INTO `goods` (id, goods_name, price)  VALUES(20, '苹果手机', 30);
SELECT * FROM goods;
——————————————————————————————————————————————————————————————
02.《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);INSERT INTO `goods` (id, goods_name) VALUES(40, 'vovo手机');(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, '格力手机');

02.update 语句

01.要求: 《在上面创建的employee表中修改表中的纪录》-- 1. 将所有员工薪水修改为5000元。[如果没有带where 条件,会修改所有的记录,因此要小心]
update em set salary=5000;-- 2. 将姓名为 小妖怪 的员工薪水修改为3000元。
update em set salary = 3000 where name = '小妖怪'; -- 3. 将 老妖怪 的薪水在原有基础上增加1000元
insert into em values(200,'老妖怪','1990-11-11','2000-11-11 10:10:10','厨子',5000,'给大王做饭','d:\\a.jpg'
);
update em set salary=salary+1000 where name='老妖怪';-- 可以修改多个列的值
update em set salary=salary+1000, job='出主意的' where name='老妖怪' ;select * from em;
——————————————————————————————————————————————————————————————
02.《update 细节说明》:(1)update 语法可以用新值更新原有表行中的各列。
(2)set子句指示要修改哪些列和要给予哪些值。
(3)where子句指定应更新哪些行;若没有where子句,则更新所有的行(记录)。(4)如果需要修改多个字段的值,可通过 [set 字段1=值1, 字段2=值2, ......]:格式:【update 表名 set 字段1=值1, 字段2=值2, ......】例子: update em set salary=salary+1000, job='出主意的' where name='老妖怪';

03.delete 语句

01.按一下需求完成:--  删除表中名称为’老妖怪’的记录。
delete from em where name='老妖怪';--  删除表中所有记录, 老师提醒,一定要小心
delete from em;-- Delete语句不能删除某一列的值(可使用update 设为 null 或者 '')
update em set job='' where name='老妖怪';select * from em;-- 要删除这个表
drop table em;
——————————————————————————————————————————————————————————————
02.《delete 细节说明》:(1)若不使用where子句,将删除表中所有数据。
(2)delete语句不能删除某一列的值,但可以使用update设为null 或 空字符串:''。
(3)使用delete子句仅删除记录,不删除表本身。如要删除表,使用drop table语句。格式:【drop table 表名;】

04.1.select 语句:单表

【基本语法】:查询表中所有信息:【select * from 表名;】-- select:指定查询哪些列的数据
-- column:指定列名
-- * 号  : 代表查询所有的列
-- from  :指定查询哪张表
-- distinct:可选,指显示结果时,是否去掉重复数据

(0.1)各个关键字的顺序

  • select 查询的字段信息 from 表名 where 普通字段条件 group by 分组字段名 having 聚合函数条件 order by 排序字段名 desc limit 跳过条数,请求条数;
select 查询的字段信息 from 表名 where 普通字段条件 group by 分组字段名 having 聚合函数条件 order by 排序字段名 limit 跳过条数,请求条数;

(0.2)主键

1、主键约束
2、主键约束 + 自增
1、《主键约束》
主键:      表示数据唯一性的字段称为主键
约束:      创建表时,给表字段添加的限制条件
主键约束:  限制主键的值 唯一且非空.如何使用:use day2db;create table t1 (id int primary key,name varchar(50))charset=utf8;insert into t1 values(1,"aaa");insert into t1 values(1,"bbb");//报错 主键值重复insert into t1 values(null,"ccc");//报错 限制主键的值 唯一且非空.
——————————————————————————————————————————————————————————————————————————————————
2、《主键约束 + 自增》
自增规则:   从历史最大值基础上+1如何使用:   create table t2(id int primary key auto_increment,name varchar(50))charset=utf8;下面每次插入属性后都可用【select * from t2;】来查看一下表格的变化:insert into t2 values(null,"aaa");insert into t2 values(null,"bbb");insert into t2 values(10,"ccc");insert into t2 values(null,"ddd");delete from t2 where id>=10;insert into t2 values(null,"eee");在 数据库 中的真实表现:
MariaDB [day2db]> select * from t2;
+----+------+
| id | name |
+----+------+
|  1 | aaa  |
|  2 | bbb  |
| 10 | ccc  |
+----+------+
3 rows in set (0.000 sec)MariaDB [day2db]> insert into t2 values(null,"ddd");
Query OK, 1 row affected (0.003 sec)MariaDB [day2db]> select * from t2;
+----+------+
| id | name |
+----+------+
|  1 | aaa  |
|  2 | bbb  |
| 10 | ccc  |
| 11 | ddd  |
+----+------+

(1)去重:distinct

01.《创建表插入数据后,进行各种查询》: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,'韩顺平',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,'欧阳锋',0,100,100);
INSERT INTO student(id,NAME,chinese,english,math) VALUES(7,'黄蓉',75,65,30);
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 `name`,english FROM student;-- 过滤表中英语成绩的重复数据 用:【distinct】 。注:要查询的记录,每个字段都相同,才会去重
SELECT DISTINCT english FROM student;-- 过滤表中的重复数据,并查询出对应的名字信息
SELECT DISTINCT `name`, english FROM student;

(2)对查询的列进行运算(as:取别名)

【select 列名1, 列名2 as 新的列名 from 表名;】-- 统计每个学生的总分
SELECT `name`, (chinese+english+math) FROM student;-- 在所有学生总分加10分的情况
SELECT `name`, (chinese + english + math + 10) FROM student;-- 使用别名表示每个学生的总分数。【select 列名1, 列名2 as 新的列名 from 表名; 】
SELECT `name`, (chinese + english + math + 10) AS total_score FROM student;-- 统计关羽的总分SELECT NAME,(chinese+english+math)  FROM student WHERE NAME='关羽';-- 使用别名表示学生的数学分数
SELECT NAME,math AS math_score FROM student;

(3)运算符(>/</between…and…/like ’ %'/is null/and/or)

《模糊查询————like》:
%: 代表0或多个未知字符
_:代表1个未知字符
举例:以x开头          x%以x结尾          %x包含x            %x%第二个字符是x     _x% 以x开头以y结尾    x%y第二个是x倒数第三个是y   _x%y__《数值计算 + - * / %》:
-- 查询每个学生的姓名,语文成绩都变成一半的成绩SELECT NAME,chinese/2 FROM student;
-- 给id为3的学生语文成绩加5分update student set chinese=chinese+5 where id=3;《is null    和    is not null》:
-- 查询有成绩的学生姓名和idselect name,id from student where id is not null;
-- 查询没有名字的学生语文成绩select name,chinese from student where name is null;

-- 查询姓名为赵云的学生成绩 【 = 等于 】
两种方式:
SELECT * FROM student WHERE `name` = '赵云';
SELECT NAME,chinese,english,math FROM student WHERE NAME='赵云';-- 查询英语成绩大于90分的同学姓名 【 > 大于 】
SELECT NAME FROM student WHERE english>90; -- 查询总分大于200分的所有同学
SELECT * FROM student WHERE (chinese+english+math)>200;-- 查询math大于60 并且(and) id大于4的学生成绩 【 and 多个条件同时成立 】
SELECT * FROM student WHERE math >60 AND id > 4;-- 查询出张飞和关羽的信息  【or 多个条件任一成立】
select * from student where name="张飞" or name="关羽";
-- -- 查询英语成绩大于语文成绩的同学
SELECT NAME FROM student WHERE english>chinese;-- 【 like ' %'  模糊查询】
-- 查询总分大于200分 并且 数学成绩小于语文成绩,的姓赵的学生信息
-- 赵% 表示 名字以韩开头的就可以SELECT * FROM student WHERE (chinese+english+math)>200AND math<chinese AND NAME LIKE '赵%';-- 【 like ' %'  模糊查询】
-- 查询名字姓黄的信息
select * from student where name like "黄%";-- 【 like ' %'  模糊查询】
-- 查询名字以飞结尾的学生姓名
select name from student where name like "%飞";-- 查询语文分数在 70-80之间的同学信息。【 between .. and .. 两者之间】
SELECT * FROM student WHERE chinese BETWEEN 70 AND 80;
SELECT * FROM student WHERE chinese>=70 AND chinese<=80;-- 查询数学分数为89,90,91的同学信息。【 in关键字: in(值1,值2,值3) 在显示在in列表中的值 】
SELECT * FROM student WHERE math = 89 OR math = 90 OR math = 91;
SELECT * FROM student WHERE math IN(89, 90, 91);-- 查询所有姓韩/宋的学生成绩。【like 姓%】
SELECT * FROM student WHERE NAME LIKE '韩%' OR NAME LIKE '宋%';-- 查询数学分>80,语文分>80的同学
SELECT * FROM student WHERE math>80 AND chinese>80;-- 查询总分为209,221,257的同学  【 or 多个条件任一成立 】SELECT * FROM student WHERE (chinese+english+math)=209OR (chinese+english+math)=221OR (chinese+english+math)=257;-- 查询数学比语文多30分的同学
SELECT * FROM student WHERE math-chinese>30;

(4)排序查询结果:order by

格式:
select 要查询的列名1,要查询的列名2 as 别名 from 表名 where 条件语句 order by 表的别名 [desc:可选,降序  asc:默认不用写,升序];(1)order by 指定排序的列,排序的列既可以是表中的列名,又可以是select语句后指定的列名
(2)asc:升序(默认)    desc:降序
(3)order by 子句应位于select语句的结尾。
-- 对数学成绩排序后输出【升序】。
select * from student order by math;-- 对数学成绩排序后输出【降序】。
select * from student order by math desc;-- 对总分按从高到低的顺序输出 [降序] -- 使用别名排序
select name,(chinese+english+math) as tocal_score from student order by tocal_score desc; -- 对姓韩的学生成绩[总分]排序输出(升序) where + order by
有三种写法:
①:
select name,(chinese+english+math) as tocal_score from student where name like'韩%' order by tocal_score;②:
SELECT `name`, (chinese + english + math) AS tocal_score FROM student WHERE NAME LIKE '韩%' ORDER BY (chinese + english + math);

(5)聚合函数:count/sum/avg/max min

通过聚合函数可以对查询的多条数据进行统计查询,
统计查询的方式包括:  求平均值, 求最大值,求最小值,求和,计数
01.《count(*):返回行的总数》
-- 统计一个班级共有多少学生?
SELECT COUNT(*) FROM student;-- 统计数学成绩大于90的学生有多少个?
SELECT COUNT(*) FROM student WHERE math>90;-- 统计总分大于250的人数有多少?SELECT COUNT(*) FROM studentWHERE (math + english + chinese)>250;问:count(*) 和 count(列) 的区别
答:①count(*): 返回满足条件的记录的行数②count(列): 统计满足条件的某列有多少个,但是会排除 为null的情况
例:
CREATE TABLE t(`name` VARCHAR(20));INSERT INTO t VALUES('tom');INSERT INTO t VALUES('jack');INSERT INTO t VALUES('mary');INSERT INTO t VALUES(NULL);SELECT * FROM t;             -- 查看表的数据SELECT COUNT(*) FROM t;      -- 查看表中返回的总行数:返回4SELECT COUNT(`name`) FROM t; -- 查看表中该列名的总行数:返回3行
———————————————————————————————————————————————————
02.《sum 的使用》:
————>sum:仅对数值起作用,没有意义
————>对多列求和,逗号不能少
————>格式:【select sum(列名1+列名2),sum(列名3+列名4) [此处可以取别名:as 别名] from 表名 [此处可以加条件:where 条件];】-- 统计一个班级数学总成绩?
SELECT SUM(math) FROM student;-- 统计一个班级语文、英语、数学各科的总成绩 [对多列求和,逗号不能少]SELECT SUM(chinese),SUM(english),SUM(math) FROM student;-- 统计一个班级语文、英语、数学的成绩总和
SELECT SUM(math + english + chinese) FROM student;-- 统计一个班级语文成绩平均分
SELECT SUM(chinese)/ COUNT(*)  FROM student;-- 统计一个班级所有同学的名字
SELECT `name` FROM student;
———————————————————————————————————————————————————
03.《avg 的使用》:
————>avg:返回满足where条件的一列的平均值
————>格式:【select avg(列名1+列名2) from 表名 [where 条件];】-- 求一个班级数学平均分?
SELECT AVG(math) FROM student;-- 求一个班级总分平均分
SELECT AVG(math + english + chinese) FROM student;
———————————————————————————————————————————————————
04.《max/min 的使用》:
————>max/min:返回满足条件的一列的最大/最小值
————>格式:【select max/min(列名) from 表名 [where 条件];】-- 演示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;

(6)分组统计+条件过滤:group by+having

(6)group by+having:(分组统计+条件过滤)group by:对列进行分组(用于对查询的结果分组统计)
格式:select 列名1,列名2,列名3,... from 表名 group by 列名having  :对分组后的结果进行过滤(用于限制分组显示结果)后面可以包含聚合函数的条件,需要和group by结合使用,写在group by的后面(where后面只能写普通字段的条件,不能包含聚合函数)
格式:select 列名1,列名2,列名3,... from 表名 group by 列名 having——————————————————————————————————————————————————————————————————————————————————
-- 01.创建部门表:
CREATE TABLE dept( /*部门表*/
deptno MEDIUMINT   UNSIGNED  NOT NULL  DEFAULT 0,
dname VARCHAR(20)  NOT NULL  DEFAULT "",
loc VARCHAR(13) NOT NULL DEFAULT ""
);
-- 添加测试数据
INSERT INTO dept VALUES(10, 'ACCOUNTING', 'NEW YORK'), (20, 'RESEARCH', 'DALLAS'), (30, 'SALES', 'CHICAGO'), (40, 'OPERATIONS', 'BOSTON');
SELECT * FROM dept;-- 02.创建员工表:
CREATE TABLE emp(empno  MEDIUMINT UNSIGNED  NOT NULL  DEFAULT 0, /*编号*/ename VARCHAR(20) NOT NULL DEFAULT "", /*名字*/job VARCHAR(9) NOT NULL DEFAULT "",/*工作*/mgr MEDIUMINT UNSIGNED ,/*上级编号*/hiredate DATE NOT NULL,/*入职时间*/sal DECIMAL(7,2)  NOT NULL,/*薪水*/comm DECIMAL(7,2) ,/*红利 奖金*/deptno MEDIUMINT UNSIGNED NOT NULL DEFAULT 0 /*部门编号*/
);
-- 添加测试数据
INSERT INTO emp VALUES
(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;-- 03.创建工资级别表:
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);
SELECT * FROM salgrade;
SELECT * FROM dept;
SELECT * FROM emp;
————————————————————————————————————————————————————————————
————————————————————————————————————————————————————————————
04.《演示group by + having》:-- ①如何显示每个部门(deptno)的平均工资和最高工资-- 分析: avg(sal) max(sal)-- 1. 按照部门来分组查询:SELECT AVG(sal), MAX(sal) , deptno FROM emp GROUP BY deptno; -- 2. 还使用数学方法,对小数点进行处理::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. 显示各个部门的平均工资和部门号:SELECT AVG(sal), deptno FROM emp GROUP BY deptno-- 2. 在1的结果基础上,进行过滤,保留 AVG(sal) < 2000:SELECT AVG(sal), deptno FROM emp GROUP BY deptnoHAVING AVG(sal) < 2000;-- 3. 使用别名进行过滤       :SELECT AVG(sal) AS avg_sal, deptno FROM emp GROUP BY deptnoHAVING avg_sal < 2000;

(7)分页查询:limit

格式: limit 跳过的条数,请求的条数(每页的条数)跳过的条数=(请求页数-1)*每页条数
举例: 查询第1页的5条数据(1-5条)        limit 0,5查询第2页的5条数据(6-10条)  limit 5,5请求第1页的10条数据            limit 0,10请求第3页的10条数据           limit 20,10
————————————————————————————————————————————————————————————————————
《练习》:————————————>需创建一个emp表来练习:
# 创建emp表(注意在idea中连接数据库写sql语句的格式和SQLYog可视化工具中不同):
DROP TABLE IF EXISTS emp;
CREATE TABLE emp (id INT(4) NOT NULL AUTO_INCREMENT,NAME VARCHAR(10) NOT NULL,job VARCHAR(9) DEFAULT NULL,manager INT(4) DEFAULT NULL,hiredate DATE DEFAULT NULL,sal DOUBLE(7,2) DEFAULT NULL,comm DOUBLE(7,2) DEFAULT NULL,dept_id INT(4) DEFAULT NULL,PRIMARY KEY (id)
) ENGINE=INNODB AUTO_INCREMENT=12 DEFAULT CHARSET=utf8;# 给emp表中添加数据:
INSERT INTO `emp`(id,NAME,job,manager,hiredate,sal,comm,dept_id
) VALUES (1,'孙悟空','销售职员',4,'1980-12-17',1800.00,100.00,1),(2,'猪八戒','销售职员',4,'1981-02-20',1600.00,300.00,1),(3,'沙僧啊','销售职员',4,'1981-02-22',5550.00,500.00,1),(4,'唐僧啊','销售经理',8,'1981-04-02',2975.00,200.00,1),(5,'刘备啊','项目经理',7,'1981-09-28',1250.00,400.00,3),(6,'关羽啊','程序员啊',5,'1981-05-01',2850.00,200.00,3),(7,'张飞啊','程序员啊',5,'1981-06-09',2450.00,100.00,3),(8,'观音啊','总经理啊',2,'1981-11-17',5000.00,300.00,1),(9,'白骨精','人力资源',8,'1981-09-08',1500.00,500.00,2),(10,'蜘蛛精','人力资源',8,'1981-12-03',950.00,NULL,2),(11,'黑熊怪','市场职员',8,'1981-12-03',900.00,NULL,2);# 查询工资最低的3个员工的信息(按照工资升序排序的第一页的3条数据)
select * from emp order by sal limit 0,3;# 按照入职日期(hiredate) 升序排序 查询第3页的3条数据
select * from emp order by hiredate limt 6,3;# 查询工资最高的员工信息
select * from emp order by sal desc limit 0,1;# 查询按照工资降序第2页的5条数据
select * from emp order by sal desc limit 5,5;

(8)字符串相关函数:ucase/replace/substring…

《在数据库【hsp_db02】中对表【emp】操作:》:#创建一个使用utf8字符集的hsp_db02数据库,默认不区分大小写
# mysql 的:utf8是三个字节的阉割版utf8编码 / utf8mb4 是完整的utf8编码
CREATE DATABASE hsp_db02 CHARACTER SET utf8;# 删除emp表
DROP TABLE emp;# 创建emp表
CREATE TABLE `emp` (`empno` MEDIUMINT(8) UNSIGNED NOT NULL DEFAULT '0', /*编号*/`ename` VARCHAR(20) COLLATE utf8_bin NOT NULL DEFAULT '""', /*名字*/`job` VARCHAR(9) COLLATE utf8_bin NOT NULL DEFAULT '""', /*工作*/`mgr` MEDIUMINT(8) UNSIGNED DEFAULT NULL, /*上级编号*/`hiredate` DATE NOT NULL, /*入职时间*/`sal` DECIMAL(7,2) NOT NULL, /*薪水*/`comm` DECIMAL(7,2) DEFAULT NULL, /*红利*/`deptno` MEDIUMINT(8) UNSIGNED NOT NULL DEFAULT 0 /*部门编号*/
) ENGINE=MYISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin;# 给emp表添加数据:
INSERT INTO emp VALUES(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',7968,'1991-2-22',1250.00,500.00,30),(7566,'JONES','MANAGER',7839,'1991-4-2',2975.00,NULL,20),(7654,'MARTIN','SALESMAN',7968,'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,'1991-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,'1991-1-23',1300.00,NULL,10);
————————————————————————————————————————————————————————————————————————
-- 演示字符串相关函数的使用 , 使用上面的 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;
SELECT RIGHT(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;

(9)数学相关函数:abs()/bin()/ceiling()…

-- 用上面的【数据库:hsp_db02中的emp表】
-- 演示数学相关函数 -- 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; -- 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;

(10)时间日期相关函数:CURRENT_DATE()…

-- 日期时间相关函数: -- 创建测试表 信息表
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;-- 练习题:
-- 查询年月日-- CURRENT_DATE( ) 当前日期: SELECT CURRENT_DATE() FROM DUAL; -- ①年月日分开显示:例:YEAR(NOW()) MONTH(NOW()) DAY(NOW())2022           10           25SELECT YEAR(NOW()),MONTH(NOW()),DAY(NOW());-- ②年月日一起显示:例:DATE(NOW())2022-10-25SELECT DATE(NOW());SELECT DATE_FORMAT(NOW(),'%Y-%m-%d'); -- 查询当前时间(时分秒)-- CURRENT_TIME( ) 当前时间 SELECT CURRENT_TIME() FROM DUAL; SELECT TIME(NOW());-- 查询当前时间(年月日时分秒):      -- CURRENT_TIMESTAMP( ) 当前时间戳(年月日时分秒) SELECT CURRENT_TIMESTAMP() FROM DUAL; SELECT NOW();-- DATE() 返回datetime(日期时间)的日期部分
SELECT DATE(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;
——————————————————————————————————————————————————————————————————————————————————————
-- [练习]:-- 如果你1986-11-11 出生,能活 80 岁,求出你还能活多少天. -- 先求出活 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

(11)加密和系统函数:user()/database()/md5()…

-- 演示加密函数和系统函数 -- USER() 查询用户
-- 可以查看登录到 mysql 的有哪些用户,以及登录的 IP
SELECT USER() FROM DUAL; -- 用户@IP 地址
-- DATABASE()查询当前使用数据库名称
SELECT DATABASE(); -- MD5(str) 为字符串算出一个 MD5 32 的字符串,常用(用户密码)加密
-- root 密码是 hsp -> 加密 md5 -> 在数据库中存放的是加密后的密码
SELECT MD5('hsp') FROM DUAL;
-- 查询该MD5字符串的长度
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 -- SQL 注入问题
SELECT * FROM hsp_user 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

(12)流程控制函数:if()/ifnull()…

# 演示流程控制语句: # 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
-- 查询jack:
SELECT CASE WHEN TRUE THEN '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;

04.2.select 语句:多表(关联关系)

  • 指创建的表和表之间存在的业务关系
  • 有哪几种关系?————>(一对一、一对多、多对多)
(1)《表和表之间如何建立关系: 通过外键字段》一对一(不重复的外键):   在AB任意一张表里面添加一个建立关系的字段(外键) 指向另外一张表的主键一对多(允许重复的外键): 在一对多的两张表中, 在"多"的表里面添加建立关系的字段 指向另外一张表的主键多对多(中间关系表):     创建一个单独的关系表, 表里面有两个字段指向另外两个表的主键如下图:

①一对一: 有AB两张表,A表中的一条数据对应B表中的一条数据, 同时B表中的一条数据也对应A表中的一条数据

②一对多:有AB两张表,A表中一条数据对应B表中的多条数据, 同时B表中的一条数据对应A表中的一条.

③多对多: 有AB两张表,A表中一条数据对应B表中的多条数据, 同时B表中的一条数据也对应A表中的多条.

(1.0)关联查询:使用empdb数据库中的表完成:

《关联查询》:同时查询多张表数据的查询方式 《关联查询包括》: 等值连接、内连接、外连接
——————————————————————————————————————————————————————————————————————
-- 创建 empdb 数据库(若不存在则创建):
CREATE DATABASE  IF NOT EXISTS `empdb` DEFAULT CHARACTER SET utf8;
USE `empdb`;-- 如果dept表存在则删除:
DROP TABLE IF EXISTS `dept`;
-- 创建表 dept:
CREATE TABLE `dept` (`id` INT(4) NOT NULL AUTO_INCREMENT,`name` VARCHAR(14) NOT NULL,`loc` VARCHAR(13) DEFAULT NULL,PRIMARY KEY (`id`),UNIQUE KEY `DNAME` (`name`)
) ENGINE=INNODB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;-- 给dept表添加数据:
INSERT  INTO `dept`(`id`,`name`,`loc`)VALUES (1,'神仙','天庭'),(2,'妖怪','盘丝洞'),(3,'普通人','北京'),(4,'赛亚人','外星球');
-- 查询该表:
SELECT * FROM dept;-- 如果emp表存在则删除:
DROP TABLE IF EXISTS emp;
-- 创建表 emp:
CREATE TABLE emp (id INT(4) NOT NULL AUTO_INCREMENT,NAME VARCHAR(10) NOT NULL,job VARCHAR(9) DEFAULT NULL,manager INT(4) DEFAULT NULL,hiredate DATE DEFAULT NULL,sal DOUBLE(7,2) DEFAULT NULL,comm DOUBLE(7,2) DEFAULT NULL,dept_id INT(4) DEFAULT NULL,PRIMARY KEY (id)
) ENGINE=INNODB AUTO_INCREMENT=12 DEFAULT CHARSET=utf8;-- 给emp表添加数据:
INSERT INTO `emp`(id,NAME,job,manager,hiredate,sal,comm,dept_id
) VALUES (1,'孙悟空','销售职员',4,'1980-12-17',1800.00,100.00,1),(2,'猪八戒','销售职员',4,'1981-02-20',1600.00,300.00,1),(3,'沙僧啊','销售职员',4,'1981-02-22',5550.00,500.00,1),(4,'唐僧啊','销售经理',8,'1981-04-02',2975.00,200.00,1),(5,'刘备啊','项目经理',7,'1981-09-28',1250.00,400.00,3),(6,'关羽啊','程序员啊',5,'1981-05-01',2850.00,200.00,3),(7,'张飞啊','程序员啊',5,'1981-06-09',2450.00,100.00,3),(8,'观音啊','总经理啊',2,'1981-11-17',5000.00,300.00,1),(9,'白骨精','人力资源',8,'1981-09-08',1500.00,500.00,2),(10,'蜘蛛精','人力资源',8,'1981-12-03',950.00,NULL,2),(11,'黑熊怪','市场职员',8,'1981-12-03',900.00,NULL,2);
-- 查询该表:
SELECT * FROM emp;

(1.1)关联查询之——等值连接(inner join)

概念:   inner join(等值连接): 只返回两个表中联结字段相等的行
格式:    select * from A,B where 关联关系(1)查询每个员工的姓名和对应的部门名   select e.name,d.name  按回车  from emp e,dept d where e.dept_id=d.id; 回车(2)查询工资高于2000的员工的姓名和对应的部门名select e.name,d.name  按回车from emp e,dept d where e.dept_id=d.id and sal>2000;  回车

(1.2)关联查询之——内连接(join … on)

等值连接和内连接查询到的是一样的数据, 推荐使用内连接格式:    select * from A join B on 关联关系(1)查询每个员工的姓名和对应的部门名select e.name,d.namefrom emp e join dept d on e.dept_id=d.id;(2)查询工资高于2000的员工姓名和对应的部门名   select e.name,d.name,salfrom emp e join dept d on e.dept_id=d.id where sal>2000;

(1.3)关联查询之——外连接(left/right join … on)

等值连接 和 内连接 查询到的 都是两个表的交集数据外连接查询到的是: 一张表的全部和另外一张表的交集-  left join(左联接) :把左边的全部查出来,右边有的则匹配,没有则为null-  right join(右联接) :返回包括右表中的所有记录,和左表中联结字段相等的记录格式:
select * from A left/right join B on 关联关系 where 其它条件;(1)查询所有员工姓名和对应的部门名:首先在表emp中插入灭霸:  insert into emp(name,sal) values("灭霸",5);再查询所有员工姓名和对应的部门名(此时查灭霸是查不到的):select e.name,d.name from emp e      join dept d on e.dept_id=d.id;   * 需要加left 或 right 才可查到:select e.name,d.name from emp e left join dept d on e.dept_id=d.id;(2)查询所有部门的名称,地点和对应的员工姓名和工资  (可以查询到赛亚人的信息)select d.name,loc,e.name,sal from emp e right join dept d on e.dept_id=d.id;

(1.4)如何查询多对多表中的数据

前提:
查询所有数据库: show databases;
用empdb数据库:use empdb;1.创建表:
create table student(id int primary key auto_increment,name varchar(50))charset=utf8;create table teacher(id int primary key auto_increment,name varchar(50))charset=utf8;create table t_s(tid int,sid int);查看所有表:   show tables;2.插入数据
insert into student values(null,"小明"),(null,"小红"),(null,"小绿"),(null,"小狗"),(null,"小黄");
查看该表内所有字段:  desc student;insert into teacher values(null,"苍老师"),(null,"传奇哥");
desc teacher;insert into t_s values(1,1),(1,5),(1,4),(2,2),(2,3),(2,1),(2,5);
desc t_s;3.
(1)查询每个老师对应的学生select t.name,s.name   按回车from teacher t join t_s ts on t.id=ts.tid   按回车join student s on s.id=ts.sid;  按回车后就会出现多对多表格(2)查询苍老师的学生都有谁?select s.name from teacher t join t_s ts on t.id=ts.tid join student s on s.id=ts.sid where t.name="苍老师";(3)查询小明的老师是谁?select t.name from teacher t join t_s ts on t.id=ts.tid join student s on s.id=ts.sid where s.name="小明";

(2)关联查询总结

1、 如果需要同时查询多张表的数据使用《关联查询》
2、 《关联查询包括》:等值链接,内连接和外连接
3、 等值链接和内连接查询的是两个表的交集数据, 推荐使用《内连接》
4、 如果需要查询一张表的全部和另外一张表的交集时 使用《外连接》,只需要掌握左外即可,因为表的位置可以交换

(3)面试题:多表设计

2021年过年时小明在这些天都收到了许多亲戚\朋友还有同事的红包,也发出了一些红包,
有的是微信,有的是支付宝也有现金,请参考下面的题目帮小明设计表格保存红包的信息
(至少包含一张流水表)
先列出需要保存的数据有哪几种1、设计表 01.创建流水表 和 人物表: (1)创建流水表:id,红包金额,时间,红包类型代码:use empdb;create table trade(id int primary key auto_increment,money int,time date,type varchar(10),person_id int)charset=utf8;(2)创建人物表: id,名字,性别,关系代码:create table person(id int primary key auto_increment,name varchar(50),gender char(1),rel varchar(5))charset=utf8;02.准备数据:       (1)流水表中:————>插入流水数据: 刘德华 微信    收1000        2021-03-20杨幂   现金    收500   发50  2021-04-14马云   支付宝  收20000 发5   2021-03-11特朗普 微信    收2000        2021-05-18貂蝉   微信    发20000       2021-07-22代码:insert into trade values(null,1000,"2021-03-20","微信",1),(null,500,"2021-04-14","现金",2),(null,-50,"2021-04-14","现金",2),(null,20000,"2021-03-11","支付宝",3),(null,-5,"2021-03-11","支付宝",3),(null,2000,"2021-05-18","微信",4),(null,-20000,"2021-07-22","微信",5);(2)人物表中:————>插入人物数据:刘德华 男 亲戚 ,杨幂 女 亲戚 ,马云 男 同事,特朗普 男 朋友, 貂蝉 女 朋友    代码:insert into person values(null,'刘德华','男','亲戚'),(null,'杨幂','女','亲戚'),(null,'马云','男','同事'),(null,'特朗普','男','朋友'),(null,'貂蝉','女','朋友');2、统计2021年2月15号到现在的所有红包收益代码:————————> select sum(money) from trade where time>"2021-7-15";数据库中代码实现:MariaDB [empdb]> select sum(money) from trade where time>"2021-7-15";+------------+| sum(money) |+------------+|     -20000 |+------------+3、查询2021年2月15号到现在 金额大于100 所有女性亲戚的名字和金额(关联查询)代码:select name,moneyfrom person p join trade t on p.id=t.person_idwhere time>"2021-2-15" and money not between -100 and 100 and gender="女"    and rel="亲戚";数据库代码实现:MariaDB [empdb]> select name,money-> from person p join trade t on p.id=t.person_id-> where time>"2021-2-15" and money not between -100 and 100 and gender="女" and rel="亲戚";+------+-------+| name | money |+------+-------+| 杨幂 |   500 |+------+-------+4、查询三个平台(微信,支付宝,现金)分别收入的红包金额  代码:select type,sum(money) from trade where money>0 group by type;数据库代码实现:MariaDB [empdb]> select type,sum(money) from trade where money>0 group by type;+--------+------------+| type   | sum(money) |+--------+------------+| 微信   |       3000 || 支付宝 |      20000 || 现金   |        500 |+--------+------------+

04.3.select语句:多表(子查询)

子查询:    是指嵌入在其它 sql 语句中的 select 语句,也叫嵌套查询
单行子查询:是指只返回一行数据的子查询语句
多行子查询:指返回多行数据的子查询 使用关键字 in
多列子查询:指查询返回多个列数据的子查询语句

(1)子查询(嵌套查询):使用empdb数据库

-- 创建 empdb 数据库(若不存在则创建):
CREATE DATABASE  IF NOT EXISTS `empdb` DEFAULT CHARACTER SET utf8;
USE `empdb`;-- 如果dept表存在则删除:
DROP TABLE IF EXISTS `dept`;
-- 创建表 dept:
CREATE TABLE `dept` (`id` INT(4) NOT NULL AUTO_INCREMENT,`name` VARCHAR(14) NOT NULL,`loc` VARCHAR(13) DEFAULT NULL,PRIMARY KEY (`id`),UNIQUE KEY `DNAME` (`name`)
) ENGINE=INNODB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;-- 给dept表添加数据:
INSERT  INTO `dept`(`id`,`name`,`loc`)VALUES (1,'神仙','天庭'),(2,'妖怪','盘丝洞'),(3,'普通人','北京'),(4,'赛亚人','外星球');-- 如果emp表存在则删除:
DROP TABLE IF EXISTS emp;
-- 创建表 emp:
CREATE TABLE emp (id INT(4) NOT NULL AUTO_INCREMENT,NAME VARCHAR(10) NOT NULL,job VARCHAR(9) DEFAULT NULL,manager INT(4) DEFAULT NULL,hiredate DATE DEFAULT NULL,sal DOUBLE(7,2) DEFAULT NULL,comm DOUBLE(7,2) DEFAULT NULL,dept_id INT(4) DEFAULT NULL,PRIMARY KEY (id)
) ENGINE=INNODB AUTO_INCREMENT=12 DEFAULT CHARSET=utf8;-- 给emp表添加数据:
INSERT INTO `emp`(id,NAME,job,manager,hiredate,sal,comm,dept_id
) VALUES (1,'孙悟空','销售职员',4,'1980-12-17',1800.00,100.00,1),(2,'猪八戒','销售职员',4,'1981-02-20',1600.00,300.00,1),(3,'沙僧啊','销售职员',4,'1981-02-22',5550.00,500.00,1),(4,'唐僧啊','销售经理',8,'1981-04-02',2975.00,200.00,1),(5,'刘备啊','项目经理',7,'1981-09-28',1250.00,400.00,3),(6,'关羽啊','程序员啊',5,'1981-05-01',2850.00,200.00,3),(7,'张飞啊','程序员啊',5,'1981-06-09',2450.00,100.00,3),(8,'观音啊','总经理啊',2,'1981-11-17',5000.00,300.00,1),(9,'白骨精','人力资源',8,'1981-09-08',1500.00,500.00,2),(10,'蜘蛛精','人力资源',8,'1981-12-03',950.00,NULL,2),(11,'黑熊怪','市场职员',8,'1981-12-03',900.00,NULL,2);
use empdb;
——————————————————————————————————————————————————————————————————————
——————————————————————————————————————————————————————————————————————
《练习》:-- 查询工资大于2号部门平均工资的员工信息首先查询 2号部门平均工资的员工信息:  select avg(sal) from emp where dept_id=2;再查询工资大于2号部门...:       select * from emp where sal>(select avg(sal) from emp where dept_id=2);-- 查询工资高于程序员最高工资的员工信息首先查询程序员最高工资的员工信息:select max(sal) from emp where job="程序员";再查询工资高于...:select * from emp where sal>(select max(sal) from emp where job="程序员");-- 查询工资最高的员工信息首先查询emp表中工资最高的信息:select max(sal) from emp;再查询表中工资最高的员工信息:select * from emp where sal=(select max(sal) from emp);-- 查询和孙悟空相同工作的员工信息首先查询孙悟空工作的信息:select job from emp where name="孙悟空";再查询和孙悟空相同工作的员工信息:select * from emp where job=(select job from emp where name="孙悟空") and name!="孙悟空";-- 查询拿最低工资员工的同事们的信息(同事指同一部门)首先查最低工资:select min(sal) from emp;再查询拿最低工资的部门:select dept_id from emp where sal=(select min(sal) from emp);最后查询拿最低工资员工的同事们的信息:select * from emp where dept_id=(select dept_id from emp where sal=(select min(sal) from emp)) and sal!=(select min(sal) from emp);

(2)多行子查询:使用部门/员工emp/工资级别 表

  • 指返回多行数据的子查询 使用关键字 in
  • 《在多行子查询中使用 all 操作符》
  • 《在多行子查询中使用 any 操作符》
-- 01.创建部门表:
DROP TABLE IF EXISTS `dept`;
CREATE TABLE dept( /*部门表*/
deptno MEDIUMINT   UNSIGNED  NOT NULL  DEFAULT 0,
dname VARCHAR(20)  NOT NULL  DEFAULT "",
loc VARCHAR(13) NOT NULL DEFAULT ""
);
-- 添加测试数据
INSERT INTO dept VALUES(10, 'ACCOUNTING', 'NEW YORK'), (20, 'RESEARCH', 'DALLAS'), (30, 'SALES', 'CHICAGO'), (40, 'OPERATIONS', 'BOSTON');
SELECT * FROM dept;-- 02.创建员工表:
DROP TABLE IF EXISTS `emp`;
CREATE TABLE emp(empno  MEDIUMINT UNSIGNED  NOT NULL  DEFAULT 0, /*编号*/ename VARCHAR(20) NOT NULL DEFAULT "", /*名字*/job VARCHAR(9) NOT NULL DEFAULT "",/*工作*/mgr MEDIUMINT UNSIGNED ,/*上级编号*/hiredate DATE NOT NULL,/*入职时间*/sal DECIMAL(7,2)  NOT NULL,/*薪水*/comm DECIMAL(7,2) ,/*红利 奖金*/deptno MEDIUMINT UNSIGNED NOT NULL DEFAULT 0 /*部门编号*/
);
-- 添加测试数据
INSERT INTO emp VALUES
(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;-- 03.创建工资级别表:
DROP TABLE IF EXISTS `salgrade`;
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);
SELECT * FROM salgrade;
SELECT * FROM dept;
SELECT * FROM emp;
————————————————————————————————————————————————————————————————————
《练习》:-- 如何显示与SMITH同一部门的所有员工?先查询到 SMITH的部门号得到:SELECT deptno FROM emp WHERE ename = 'SMITH'把上面的select 语句当做一个子查询来使用:   SELECT * FROM emp WHERE deptno = (SELECT deptno FROM emp WHERE ename = 'SMITH');-- 如何查询和部门10的工作相同的雇员的(名字、岗位、工资、部门号, 但是不含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;
————————————————————————————————————————————————————————————————————
《在多行子查询中使用 all 操作符》:-- 显示工资比部门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 操作符》:-- 如何显示工资比部门30的其中一个员工的工资高的员工的姓名、工资和部门号
SELECT ename, sal, deptno FROM emp WHERE sal > ANY(SELECT sal FROM emp WHERE deptno = 30
);
-- 也可以这样写:
SELECT ename, sal, deptno FROM emp WHERE sal > (SELECT MIN(sal) FROM emp WHERE deptno = 30
);

(3)多列子查询:

  • 指查询返回多个列数据的子查询语句
-- 查询与allen的部门和岗位完全相同的所有雇员(并且不含allen本人)
-- (字段1, 字段2 ...) = (select 字段 1,字段2 from 。。。。)-- 分析: 1. 得到smith的部门和岗位
SELECT deptno , job FROM emp WHERE ename = 'ALLEN'-- 分析: 2  把上面的查询当做子查询来使用,并且使用多列子查询的语法进行匹配
SELECT * FROM emp WHERE (deptno , job) = (SELECT deptno , job FROM emp WHERE ename = 'ALLEN'
) AND ename != 'ALLEN';

04.4.select语句:合并查询(union/union all )

有时在实际应用中,
为了合并多个select语句的结构,可以使用【集合操作符号:union、union all 】1. union该操作符与 union all 相似,但是会自动去掉结果集中重复行2. union all该操作用于取得两个结果集的并集。当使用该操作符时,不会取消重复行。
————————————————————————————————————————————————————————————————————————
《练习》:使用【04.3.(2)中的emp员工表】
-- 在员工表 emp 中查询出工资大于2500的用户名/工资/工作SELECT ename,sal,job FROM emp WHERE sal>2500;
-- 查询出工作是'MANAGER'的用户名/工资/工作SELECT ename,sal,job FROM emp WHERE job='MANAGER'; -- union  就是将两个查询结果合并,会去重SELECT ename,sal,job FROM emp WHERE sal>2500 -- 5UNION SELECT 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

————————————————

三、补充

1、阿里Mysql规则

01.(一)建表规约

1. 【强制】表达是与否概念的字段,必须使用 is_xxx 的方式命名,数据类型是 unsigned tinyint( 1 表示是,0 表示否)。说明:任何字段如果为非负数,必须是 unsigned。正例:表达逻辑删除的字段名 is_deleted,1 表示删除,0 表示未删除。2. 【强制】表名、字段名必须使用小写字母或数字,禁止出现数字开头,禁止两个下划线中间只出现数字。数据库字段名的修改代价很大,因为无法进行预发布,所以字段名称需要慎重考虑。说明:MySQL 在 Windows 下不区分大小写,但在 Linux 下默认是区分大小写。因此,数据库名、表名、字段名,都不允许出现任何大写字母,避免节外生枝。正例:aliyun_admin,rdc_config,level3_name反例:AliyunAdmin,rdcConfig,level_3_name3. 【强制】表名不使用复数名词。说明:表名应该仅仅表示表里面的实体内容,不应该表示实体数量,对应于 DO 类名也是单数形式,符合表达习惯。4. 【强制】禁用保留字,如 desc、range、match、delayed 等,请参考 MySQL 官方保留字。5. 【强制】主键索引名为 pk_字段名;唯一索引名为 uk_字段名;普通索引名则为 idx_字段名。说明:pk_ 即 primary key;uk_ 即 unique key;idx_ 即 index 的简称。6. 【强制】小数类型为 decimal,禁止使用 float 和 double。说明:float 和 double 在存储的时候,存在精度损失的问题,很可能在值的比较时,得到不正确的结果。如果存储的数据范围超过 decimal 的范围,建议将数据拆成整数和小数分开存储。7. 【强制】如果存储的字符串长度几乎相等,使用 char 定长字符串类型。8. 【强制】varchar 是可变长字符串,不预先分配存储空间,长度不要超过 5000,如果存储长度大于此值,定义字段类型为 text,独立出来一张表,用主键来对应,避免影响其它字段索引效率。9. 【强制】表必备三字段:id, gmt_create, gmt_modified。说明:其中 id 必为主键,类型为 unsigned bigint、单表时自增、步长为 1。gmt_create,gmt_modified 的类型均为 date_time 类型,前者现在时表示主动创建,后者过去分词表示被动更新。10. 【推荐】表的命名最好是加上“业务名称_表的作用”。正例:alipay_task / force_project / trade_config11. 【推荐】库名与应用名称尽量一致。12. 【推荐】如果修改字段含义或对字段表示的状态追加时,需要及时更新字段注释。13. 【推荐】字段允许适当冗余,以提高查询性能,但必须考虑数据一致。冗余字段应遵循:1)不是频繁修改的字段。2)不是 varchar 超长字段,更不能是 text 字段。正例:商品类目名称使用频率高,字段长度短,名称基本一成不变,可在相关联的表中冗余存储类目名称,避免关联查询。14. 【推荐】单表行数超过 500 万行或者单表容量超过 2GB,才推荐进行分库分表。说明:如果预计三年后的数据量根本达不到这个级别,请不要在创建表时就分库分表。15. 【参考】合适的字符存储长度,不但节约数据库表空间、节约索引存储,更重要的是提升检索速度。正例:如下表,其中无符号值可以避免误存负数,且扩大了表示范围。

02.(二)索引规约

1. 【强制】业务上具有唯一特性的字段,即使是多个字段的组合,也必须建成唯一索引。说明:不要以为唯一索引影响了 insert 速度,这个速度损耗可以忽略,但提高查找速度是明显的;另外,即使在应用层做了非常完善的校验控制,只要没有唯一索引,根据墨菲定律,必然有脏数据产生。2. 【强制】超过三个表禁止 join。需要 join 的字段,数据类型必须绝对一致;多表关联查询时,保证被关联的字段需要有索引。说明:即使双表 join 也要注意表索引、SQL 性能。3. 【强制】在 varchar 字段上建立索引时,必须指定索引长度,没必要对全字段建立索引,根据实际文本区分度决定索引长度即可。说明:索引的长度与区分度是一对矛盾体,一般对字符串类型数据,长度为 20 的索引,区分度会高达 90%以上,可以使用 count(distinct left(列名, 索引长度))/count(*)的区分度来确定。4. 【强制】页面搜索严禁左模糊或者全模糊,如果需要请走搜索引擎来解决。说明:索引文件具有 B-Tree 的最左前缀匹配特性,如果左边的值未确定,那么无法使用此索引。5. 【推荐】如果有 order by 的场景,请注意利用索引的有序性。order by 最后的字段是组合索引的一部分,并且放在索引组合顺序的最后,避免出现 file_sort 的情况,影响查询性能。正例:where a=? and b=? order by c; 索引:a_b_c反例:索引中有范围查找,那么索引有序性无法利用,如:WHERE a>10 ORDER BY b; 索引a_b 无法排序。6. 【推荐】利用覆盖索引来进行查询操作,避免回表。说明:如果一本书需要知道第 11 章是什么标题,会翻开第 11 章对应的那一页吗?目录浏览一下就好,这个目录就是起到覆盖索引的作用。正例:能够建立索引的种类:主键索引、唯一索引、普通索引,而覆盖索引是一种查询的一种效果,用 explain 的结果,extra 列会出现:using index。7. 【推荐】利用延迟关联或者子查询优化超多分页场景。说明:MySQL 并不是跳过 offset 行,而是取 offset+N 行,然后返回放弃前 offset 行,返回 N 行,那当 offset 特别大的时候,效率就非常的低下,要么控制返回的总页数,要么对超过特定阈值的页数进行 SQL 改写。正例:先快速定位需要获取的 id 段,然后再关联:SELECT a.* FROM 表 1 a, (select id from 表 1 where 条件 LIMIT 100000,20 ) b where a.id=b.id8. 【推荐】SQL 性能优化的目标:至少要达到 range 级别,要求是 ref 级别,如果可以是 consts 最好。说明:1)consts 单表中最多只有一个匹配行(主键或者唯一索引),在优化阶段即可读取到数据。2)ref 指的是使用普通的索引(normal index)。3)range 对索引进行范围检索。反例:explain 表的结果,type=index,索引物理文件全扫描,速度非常慢,这个 index 级别比较 range 还低,与全表扫描是小巫见大巫。9. 【推荐】建组合索引的时候,区分度最高的在最左边。正例:如果where a=? and b=?,a列的几乎接近于唯一值,那么只需要单建idx_a 索引即
可。说明:存在非等号和等号混合判断条件时,在建索引时,请把等号条件的列前置。如:where a>? and b=? 那么即使 a 的区分度更高,也必须把 b 放在索引的最前列。阿里巴巴 Java 开发手册10. 【推荐】防止因字段类型不同造成的隐式转换,导致索引失效。11. 【参考】创建索引时避免有如下极端误解:1)宁滥勿缺。认为一个查询就需要建一个索引。2)宁缺勿滥。认为索引会消耗空间、严重拖慢更新和新增速度。3)抵制惟一索引。认为业务的惟一性一律需要在应用层通过“先查后插”方式解决

03.(三)SQL 语句

1. 【强制】不要使用 count(列名)或 count(常量)来替代 count(*),count(*)是 SQL92 定义的标准统计行数的语法,跟数据库无关,跟 NULL 和非 NULL 无关。说明:count(*)会统计值为 NULL 的行,而 count(列名)不会统计此列为 NULL 值的行。2. 【强制】count(distinct col) 计算该列除 NULL 之外的不重复行数,注意 count(distinct col1, col2) 如果其中一列全为 NULL,那么即使另一列有不同的值,也返回为 0。3. 【强制】当某一列的值全是 NULL 时,count(col)的返回结果为 0,但 sum(col)的返回结果为NULL,因此使用 sum()时需注意 NPE 问题。正例:可以使用如下方式来避免 sum 的 NPE 问题:SELECT IF(ISNULL(SUM(g)),0,SUM(g))
FROM table;4. 【强制】使用 ISNULL()来判断是否为 NULL 值。说明:NULL 与任何值的直接比较都为 NULL。1) NULL<>NULL 的返回结果是 NULL,而不是 false。2) NULL=NULL 的返回结果是 NULL,而不是 true。3) NULL<>1 的返回结果是 NULL,而不是 true。5. 【强制】在代码中写分页查询逻辑时,若 count 为 0 应直接返回,避免执行后面的分页语句。6. 【强制】不得使用外键与级联,一切外键概念必须在应用层解决。说明:以学生和成绩的关系为例,学生表中的 student_id是主键,那么成绩表中的 student_id则为外键。如果更新学生表中的 student_id,同时触发成绩表中的 student_id 更新,即为级联更新。外键与级联更新适用于单机低并发,不适合分布式、高并发集群;级联更新是强阻塞,存在数据库更新风暴的风险;外键影响数据库的插入速度。7. 【强制】禁止使用存储过程,存储过程难以调试和扩展,更没有移植性。8. 【强制】数据订正时,删除和修改记录时,要先 select,避免出现误删除,确认无误才能执行更新语句。9. 【推荐】in 操作能避免则避免,若实在避免不了,需要仔细评估 in 后边的集合元素数量,控制在 1000 个之内。10. 【参考】如果有全球化需要,所有的字符存储与表示,均以 utf-8 编码,注意字符统计函数的区别。说明:SELECT LENGTH("轻松工作"); 返回为 12SELECT CHARACTER_LENGTH("轻松工作"); 返回为 4如果需要存储表情,那么选择 utfmb4 来进行存储,注意它与 utf-8 编码的区别。11. 【参考】TRUNCATE TABLE 比 DELETE 速度快,且使用的系统和事务日志资源少,但 TRUNCATE无事务且不触发 trigger,有可能造成事故,故不建议在开发代码中使用此语句。说明:TRUNCATE TABLE 在功能上与不带 WHERE 子句的 DELETE 语句相同。

04.(四)ORM 映射

1. 【强制】在表查询中,一律不要使用 * 作为查询的字段列表,需要哪些字段必须明确写明。说明:1)增加查询分析器解析成本。2)增减字段容易与 resultMap 配置不一致。2. 【强制】POJO 类的布尔属性不能加 is,而数据库字段必须加 is_,要求在 resultMap 中进行字段与属性之间的映射。说明:参见定义 POJO 类以及数据库字段定义规定,在<resultMap>中增加映射,是必须的。在 MyBatis Generator 生成的代码中,需要进行对应的修改。3. 【强制】不要用 resultClass 当返回参数,即使所有类属性名与数据库字段一一对应,也需要定义;反过来,每一个表也必然有一个与之对应。说明:配置映射关系,使字段与 DO 类解耦,方便维护。4. 【强制】sql.xml 配置参数使用:#{},#param# 不要使用${} 此种方式容易出现 SQL 注入。5. 【强制】iBATIS 自带的: queryForList(String statementName,int start,int size)不推荐使用。说明:其实现方式是在数据库取到statementName对应的SQL语句的所有记录,再通过subList取 start,size 的子集合。正例:Map<String, Object> map = new HashMap<String, Object>();map.put("start", start);map.put("size", size);6. 【强制】不允许直接拿 HashMap 与 Hashtable 作为查询结果集的输出。说明:resultClass=”Hashtable”,会置入字段名和属性值,但是值的类型不可控。7. 【强制】更新数据表记录时,必须同时更新记录对应的 gmt_modified 字段值为当前时间。8. 【推荐】不要写一个大而全的数据更新接口。传入为 POJO 类,不管是不是自己的目标更新字段,都进行 update table set c1=value1,c2=value2,c3=value3; 这是不对的。执行 SQL时,不要更新无改动的字段,一是易出错;二是效率低;三是增加 binlog 存储。9. 【参考】@Transactional 事务不要滥用。事务会影响数据库的 QPS,另外使用事务的地方需要考虑各方面的回滚方案,包括缓存回滚、搜索引擎回滚、消息补偿、统计修正等。10. 【参考】<isEqual>中的 compareValue 是与属性值对比的常量,一般是数字,表示相等时带上此条件;<isNotEmpty>表示不为空且不为 null 时执行;<isNotNull>表示不为 null 值时执行。

《Mysql数据库》相关推荐

  1. ComeFuture英伽学院——2020年 全国大学生英语竞赛【C类初赛真题解析】(持续更新)

    视频:ComeFuture英伽学院--2019年 全国大学生英语竞赛[C类初赛真题解析]大小作文--详细解析 课件:[课件]2019年大学生英语竞赛C类初赛.pdf 视频:2020年全国大学生英语竞赛 ...

  2. ComeFuture英伽学院——2019年 全国大学生英语竞赛【C类初赛真题解析】大小作文——详细解析

    视频:ComeFuture英伽学院--2019年 全国大学生英语竞赛[C类初赛真题解析]大小作文--详细解析 课件:[课件]2019年大学生英语竞赛C类初赛.pdf 视频:2020年全国大学生英语竞赛 ...

  3. 信息学奥赛真题解析(玩具谜题)

    玩具谜题(2016年信息学奥赛提高组真题) 题目描述 小南有一套可爱的玩具小人, 它们各有不同的职业.有一天, 这些玩具小人把小南的眼镜藏了起来.小南发现玩具小人们围成了一个圈,它们有的面朝圈内,有的 ...

  4. 信息学奥赛之初赛 第1轮 讲解(01-08课)

    信息学奥赛之初赛讲解 01 计算机概述 系统基本结构 信息学奥赛之初赛讲解 01 计算机概述 系统基本结构_哔哩哔哩_bilibili 信息学奥赛之初赛讲解 02 软件系统 计算机语言 进制转换 信息 ...

  5. 信息学奥赛一本通习题答案(五)

    最近在给小学生做C++的入门培训,用的教程是信息学奥赛一本通,刷题网址 http://ybt.ssoier.cn:8088/index.php 现将部分习题的答案放在博客上,希望能给其他有需要的人带来 ...

  6. 信息学奥赛一本通习题答案(三)

    最近在给小学生做C++的入门培训,用的教程是信息学奥赛一本通,刷题网址 http://ybt.ssoier.cn:8088/index.php 现将部分习题的答案放在博客上,希望能给其他有需要的人带来 ...

  7. 信息学奥赛一本通 提高篇 第六部分 数学基础 相关的真题

    第1章   快速幂 1875:[13NOIP提高组]转圈游戏 信息学奥赛一本通(C++版)在线评测系统 第2 章  素数 第 3 章  约数 第 4 章  同余问题 第 5 章  矩阵乘法 第 6 章 ...

  8. 信息学奥赛一本通题目代码(非题库)

    为了完善自己学c++,很多人都去读相关文献,就比如<信息学奥赛一本通>,可又对题目无从下手,从今天开始,我将把书上的题目一 一的解析下来,可以做参考,如果有错,可以告诉我,将在下次解析里重 ...

  9. 信息学奥赛一本通(C++版) 刷题 记录

    总目录详见:https://blog.csdn.net/mrcrack/article/details/86501716 信息学奥赛一本通(C++版) 刷题 记录 http://ybt.ssoier. ...

  10. 最近公共祖先三种算法详解 + 模板题 建议新手收藏 例题: 信息学奥赛一本通 祖孙询问 距离

    首先什么是最近公共祖先?? 如图:红色节点的祖先为红色的1, 2, 3. 绿色节点的祖先为绿色的1, 2, 3, 4. 他们的最近公共祖先即他们最先相交的地方,如在上图中黄色的点就是他们的最近公共祖先 ...

最新文章

  1. chapter4 module and port
  2. 剑指offer 面试32题
  3. UML表示实体类型和属性
  4. Java调用Lua脚本(热载实现)
  5. Codeforces-339D. Xenia and Bit Operations
  6. 互联网Internet体系结构以及网关协议OSPF
  7. 百度地图坐标转换的异步回调事件
  8. 知识点 - 哈密顿图
  9. 2022年下半年软考报名时间汇总,最新版!
  10. 文献阅读-一种基于机器学习方法的海事监视雷达海杂波抑制方法
  11. 【数学模拟卷总结】2023李林六套卷数学二第二套
  12. Arduino实验二十五 超声波传感器测距实验
  13. Fabric CA官方文档翻译——Planning for a CA
  14. PARALYSIS AS “SPIRITUAL LIBERATION” IN JOYCE’S DUBLINERS Iven Lucas Heister, B.A.【翻译】
  15. Android Studio Win7安装
  16. win10家庭中文版安装Hyper-V 解决Hyper-V.cmd闪退问题
  17. 省选+NOI 第一部分 动态规划DP
  18. Android 仿淘宝京东商品详情页阻力翻页效果
  19. 万商云集企业SAAS服务平台
  20. 2019 前端工程师修炼手册.pdf

热门文章

  1. java调用海康威视人脸识别抓拍
  2. 最小费用最大流算法 网络流
  3. 单链表的逆转:(头尾互换)
  4. leetcode 每天10道travl
  5. 洛谷 P2888 [USACO07NOV] 牛栏Cow Hurdles
  6. 扫福活动开始,你的公众号图文排版也要“福”气满满
  7. EF core和数据库, Database First
  8. springboot~使用自定义的aspect
  9. mysql on是什么意思_这SQL语句里的ON 是什么意思啊
  10. 【ospf-vlink虚拟连接】