MySQL基础

MySQL

一、为什么要学习数据库

1.1数据库的好处

1.持久化数据到本地

2.可以实现结构化查询,方便管理

二、数据库的相关概念

2.1现有的数据存储方式有哪些?

java程序存储数据(变量、对象、数组、集合),数据保存在内存中,属于瞬时状态存储。

文件(file)存储数据,保存在硬盘上,属于持久状态存储。

2.2以上存储方式存在哪些缺点?

  • 没有数据类型的区分
  • 存储数据量级较小
  • 没有访问安全限制
  • 没有备份、恢复机制

2.3数据库的分类

  • 网状结构数据库:美国通用电气公司IDS(Integrated Data Store).以节点形式存储和访问.
  • 层级结构数据库:IBM公司IMS(Information Management System) 定向有序的树状结构实现存储和访问.
  • 关系结构数据库:Oracle、DB2、MySQL、SQL server,以表格(Table)存储,多表间建立关联关系,通过分类、合并、连接、选取等运算实现访问。
  • 非关系型数据库:ElastecSearch、MongoDB、Redis,多数使用哈希表,表中以键值(key-value)的实现特定的键和一个指针指向的特定数据。

2.4概念

​ 数据库是按照数据结构来组织、存储和管理数据的仓库。是一个长期存储在计算机内的、有组织的、有共享的、统一管理的数据集合。

​ DBMS:数据库管理系统,又称为数据库软件(产品),用于管理DB中的数据

​ DB:数据库,保存一组有组织的数据的容器

​ SQL:结构化查询语言,用于和DBMS通信的语言

2.5常见数据库管理系统

  • Oracle:被认为是业界目前比较成功的关系型数据库管理系统。Oracle数据库可以运行在UNIX、Windows等主流操作系统平台,完全支持所有的工业标准,并获得最高级别的ISO标准安全性认证。
  • DB2:IBM公司的产品,DB2数据库系统采用多进程多线索体系结构,其功能足以满足大中公司的需要,并可灵活地服务于中小型电子商务解决方案。
  • SQL Service:Microsoft公司推出的关系型数据库管理系统。具有使用方便可伸缩性好与相关软件集成程度高等优点。
  • SQLLite:应用在手机端的数据库。

三、数据库存储数据的特点

  1. 将数据库放到表中,表再放到库中
  2. 一个数据库中可以有多个表,每个表都有一个名字,用来标识自己。表名具有唯一性。
  3. 表具有一些特性,这些特性定义了数据在表中如何存储,类似Java中“类”的设计。
  4. 表由列组成,我们也称为字段。所有表都是由一个或多个列组成的,每一列类似Java中的“属性”
  5. 表中的数据是按行存储的,每一行类似于Java中的“对象”。

四、初始MySQL

4.1MySQL产品的介绍

MySQL是一个关系型数据库管理系统,由瑞典MySQL AB公司开发,属于Oracle旗下产品。MySQL是最流行的关系型数据库管理系统之一,在WEB应用方面,MySQL是最好的RDBMS(Relational Database Management System,关系数据库管理系统)应用软件之一。

4.2MySQL产品的安装

官方网站:https://www.mysql.com/

下载地址:https://dev.mysql.com/downloads/mysql/

4.3MySQL卸载

  • 控制台卸载
  • 找到MySQL的安装目录进行删除
  • programdata删除MySQL
  • 注意:如果卸载后,如有未删除的MySQL服务,可采用手动删除
  • 以管理员身份打开命令行,输入sc delete mysql57 回车。

4.4配置环境变量

  • Windows
    • 创建MYSQL_HOME:C:\Program Files\MySQL Server5.7
    • 追加PATH:%MYSQL_HOME%\bin;
  • MacOS/Linux
    • 终端中输入cd~进入目录,并检查。bash_profile 是否存在,有则追加,无则创建
    • 创建文件touch.bash_profile
    • 打开文件open.bash_profile
    • 输入export PATH=${PATH}:/usr/local/mysql/bin保存并退出终端

4.5MySQL服务的启动和停止

方式一:计算机–右击管理–服务

方式二:通过管理员身份运行

​ net start 服务名(启动服务)

​ net stop 服务名(停止服务)

4.6MySQL服务的登录和退出

方式一:通过MySQL自带的客户端 -------> 只限于root用户

方式二:通过Windows自带的客户端

​ 登录:MySQL 【-h 主机名 -p端口号】 -u用户名 -p密码

​ 退出:exit 或 ctrl + c

4.7MySQL目录结构

核心文件介绍

文件夹名称内容
bin命令文件
lib库文件
include头文件
share字符集、语言等信息

4.8MySQL配置文件

在MySQL安装目录中找到my.ini文件,并打开my.ini文件查看几个常用配置参数

参数描述
dafault-character-set客户端默认字符集
character-set-server服务器端默认字符集
port客户端和服务端的端口号
default-storage-engineMySQL默认存储引擎INNODB

五、SQL语言

5.1概念

SQL(Structured Query Language)结构化查询语言,用于存取数据、更新、查询和管理关系数据库系统的程序设计语言。

  • 经验:通常执行对数据库的“增删改查”,简称C(Create)R(Read)U(Update)D(Delete)。

5.2MySQL应用

对于数据库的操作,需要在进入MySQL环境下进行指令输入,并在一句指令的末尾使用;结束

5.3基本命令

  • 查看服务器的版本

方式一:登录到mysql服务端

select version();

方式二:没有登录到MySQL服务端

mysql  -version 或  mysql -v
  • 查看MySQL中所有数据库
mysql> show databases; #显示当前MySQL中包含的所有数据库
数据库名描述
information_schema信息数据库,其中保存着关于所有数据库的信息(元数据)。
元数据是关于数据的数据,如数据库名或表名,列的数据类型,或访问权限等。
mysql核心数据库,主要负责存储数据库的用户、权限设置、关键字等,
以及需要使用的控制和管理信息,不可以删除。
performance_schema性能优化的数据库,MySQL 5.5版本中新增的一个性能优化的引擎。
sys系统数据库,MySQL5.7版本中新增的可以快速的了解元数据信息的系统库
便于发现数据库的多样信息,解决性能瓶颈问题。
  • 创建自定义数据库
mysql> create database mydb1; #创建mydb数据库
mysql> create database mydb2 character set gbk; #创建数据库并设置编码格式为gbk
mysql> create database if not exists mydb3; #如果mydb3数据库不存在,则创建;如果存在,则不创建
  • 查看数据库创建信息
mysql> show create database mydb2; #查看创建数据库时的基本信息
  • 修改数据库的编码格式
mysql> alter database mydb2 character set gbk; #修改数据库的字符集
  • 查看当前所使用的数据库
mysql> select database(); #查看当前使用的数据库
  • 显示当前所有数据库
mysql> show databases; #显示当前所有数据库
  • 查看当前库的所有表
mysql> show tables; #查看当前库的所有表
  • 查看其它库的所有表
mysql> show tables from 库名; #查看其他库的所有表
  • 删除数据库
mysql> drop database mydb1; #删除数据库mydb1
  • 使用数据库
mysql> use mydb1; #使用mudb1数据库
  • 创建表
mysql> create table 表名(列名 列类型,列名 列类型,。。。); #创建表

查看表结构

mysql> desc 表名; #查看表结构

5.4MySQL的语法规范

  1. 不区分大小写,但建议关键字大写,表名、列名小写

  2. 每条命令最好用分号结尾

  3. 每条命令根据需要,可以进行缩进或换行

  4. 注释

    单行注释:#注释文字

    单行注释:–注释文字

    多行注释:/注释文字/

5.5SQL的语言分类

数据查询语言DQL(Data Query Language): selectwhereorder bygroup byhaving 
数据定义语言DDL(Data Definition Language): createalterdrop
数据操作语言DML(Data Manipulation Language): insertupdatedelete 
事务处理语言TPL(Transaction Process Language): commitrollback 
数据控制语言DCL(Data Control Language): grantrevoke

六、DQL语言的学习

数据库表的基本结构

关系结构数据库是以表格(Table)进行数据存储,表格由“行”和“列”组成
  • 经验:执行查询语句返回的结果集是一张虚拟表。

6.1基础查询

类似于Java中 :System.out.println(要打印的东西);
特点:
①通过select查询完的结果 ,是一个虚拟的表格,不是真实存在
② 要查询的东西 可以是常量值、可以是表达式、可以是字段、可以是函数
语法: select 列名 from 表名
关键字描述
select指定要查询的列
from指定要查询的表
6.1.1查询部分列
#查询员工表中所有员工的编号、名字、邮箱
SELECT employee_id,first_name , email
FROM t_employees;
6.1.2查询所有列
#查询员工表中所有员工的所有信息(所有列)
SELECT 所有列的列名 FROM t_employees;
SELECT * FROM t_employees;
  • *注意∶生产环境下,优先使用列名查询。的方式需转换成全列名,效率低,可读性差。
6.1.3对列中的数据进行运算
#查询员工表中所有员工的编号、名字、年薪
SELECT employee_id , first_name , salary*12
FROM t_employees;
算数运算符描述
+两列做加法运算
-两列做减法运算
*两列做乘法运算
/两列做除法运算
  • 注意:%是占位符,而非模运算符。
6.1.4列的别名

​ 列 as ‘列名’

#查询员工表中所有员工的编号、名字、年薪(列名均为中文)
SELECT employee_id as“编号”,first_name as"名字",salary*12 as"年薪""
FROM t_employees;
6.1.5查询结果去重

​ distinct列名

#查询员工表中所有经理的ID。
SELECT DISTINCT manager_id
FROM t_employees;

7.3排序查询
语法:SELECT列名FROM表名ORDER BY排序列[排序规则(列名)]asc/desc

6.2条件查询

条件查询:根据条件过滤原始表的数据,查询到想要的数据

关键字描述
where条件在查询结果中,筛选符合条件的查询结果,条件为布尔表达式
select 要查询的字段|表达式|常量值|函数 from 表名 where 条件 ;
6.2.1等值判断(=)
#查询薪资是11808的员工信息(编号、名字、薪资)
SELECT employee_id , first_name , salary
FROM t_employees
WHERE salary = 11008;
  • 注意:与java不同(==) , mysql中等值判断使用=
6.2.2逻辑判断(and、or、not)

逻辑运算符:
and(&&):两个条件如果同时成立,结果为true,否则为false
or(||):两个条件只要有一个成立,结果为true,否则为false
not(!):如果条件成立,则not后为false,否则为true

#查询薪资是11000并且提成是0.30的员工信息(编号、名字、薪资)
SELECT employee_id , first_name , salary
FROM t_employees
WHERE salary = 11000 AND commission_pct = 0.30;
6.3.3不等值判断(>、<、>=、=、!=、>)
#查询员工的薪资在6000~10000之间的员工信息(编号,名字,薪资)
SELECT employee_id , first_name , salary
FROM t_employees
WHERE salary >= 6000 AND salary <= 10000;
6.3.4区间判断(between and)
#查询员工的薪资在6000~10000之间的员工信息(编号,名字,薪资)
SELECT employee_id , first_name , salary
FROM t_employees
WHERE salary BETWEEN 6000 AND 10000;#闭区间,包含区间边界的两个值
  • 注:在区间判断语法中,小值在前,大值在后,反之,得不到正确结果
6.3.5 NULL值判断(IS NULL、IS NOT NULL)
  • IS NULL
    列名IS NULL
  • IS NOT NULL
    列名IS NOT NULL
#查询没有提成的员工信息(编号,名字,薪资,提成)
SELECT employee_id , first_name , salary , commission_pct
FROM t_employees
WHERE commission_pct IS NULL;
6.3.6枚举查询(IN(值1,值2,值3))
#查询部门编号为70、80、90的员工信息(编号,名字,薪资,部门编号)
SELECT employee_id , first_name , salary , department_id
FROM t_employees
WHERE department_id IN(70,80,90);
注:in的查询效率较低,可通过多条件拼接。
6.3.7模糊查询
  • LIKE__(单个任意字符)
    列名LIKE’张_’

  • LIKE%(任意长度的任意字符)
    列名LIKE’张%’

  • 注意:模糊查询只能和LIKE关键字结合使用

    #查询名字以"L"开头的员工信息(编号,名字,薪资,部门编号)
    SELECT employee_id , first_name , salary , department_id
    FROM t_employees
    WHERE first_name LIKE 'L%';
    
    #查询名字以"L"开头并且长度为4的员工信息(编号,名字,薪资,部门编号)
    SELECT employee_id , first_name , salary , department_id
    FROM t_employees
    WHERE first_name LIKE'L___';
    
    6.3.8分支结构查询
    CASE
    	WHEN条件1 THEN结果1
    	WHEN条件2 THEN结果2
    	WHEN条件3 THEN结果3
    	ELSE结果
    END
    
    • 注意︰通过使用CASE END进行条件判断,每条数据对应生成一个值。
    • 经验︰类似Java中的switch。
#查询员工信息(编号,名字,薪资,薪资级别<对应条件表达式生成>)
SELECT employee_id , first_name , salary , department_id ,
	CASE
		WHEN salary>=10000 THEN 'A'
		WHEN salary>=8000 AND salary<10000 THEN'B'
		WHEN salary>=6000 AND salary<8000 THEN'C'
		WHEN salary>=4000 AND salary<6000 THEN 'D'
	ELSE 'E'
		END as "LEVEL"
FROM t_employees;

6.3排序查询

select要查询的东西 from 表名 where 条件 order by 排序的字段|表达式|函数|别名 【asc|desc
排序规则描述
ASC对前面排序列做升序排序
DESC对前面排序列做降序排序
6.3.1依据单列排序
#查询员工的编号,名字,薪资。按照工资高低进行降序排序。
SELECT employee_id , first_name , salary
FROM t_employees
ORDER BY salary DESC;
6.3.2依据多列排序
#查询员工的编号,名字,薪资。按照工资高低进行升序排序(薪资相同时,按照编号进行升序排序)。
SELECT employee_id , first_name , salary
FROM t_employees
ORDER BY salary DESC , employee_id ASC;

6.4时间查询

select 时间函数(【参数列表】)

  • 经验:执行时间函数查询,会自动生成一张虚表(一行一列)
时间函数描述
SYSDATE()当前系统时间(日、月、年、时、分、秒)
CURDATE()获取当前日期
CURTIME()获取当前时间
WEEK(DATE)获取指定日期为一年中的第几周
YEAR(DATE)获取指定日期的年份
HOUR(TIME)获取指定时间的小时值
MINUTE(TIME)获取时间的分钟值
DATEDIFF(DATE1,DATE2)获取DATE1和DATE2之间相隔的天数
ADDDATE(DATE,N)计算DATE加上N天后的日期
6.4.1获取当前系统时间
#查询当前时间 (日期+时间)
select sysdate();
#查询当前时间 (日期+时间)
select now();
#获取当前日期
select curdate();
#获取当前时间
select curtime();
6.4.2日期格式
四位的年份
二位的年份
月份(01,02…12)
月份(1,2,3…12)
日(01,02,…)
小时(24小时制)
小时(12小时制)
分钟(00,01…59)
秒(00,01,…59)
str_to_date将字符转换成日期
date_format将日期转换成字符

6.5字符串查询

select 字符串函数(【参数列表】)

字符串函数说明
CONCAT(str1,str2,str…)将多个字符串连接
INSERT(str,pos,len,newStr)将str中指定pos位置开始len长度的内容替换为newStr
LOWER(str)将指定字符串转换为小写
UPPER(str)将指定字符串转换为大写
SUBSTRING(str,num,len)将str字符串指定num位置开始截取len个内容
substr截取字串
trim去前后指定的空格和字符
ltrim去左边空格
rtrim去右边空格
replace(str,from_str,to_str)替换
lpad(str,len,padstr)左填充
rpad右填充
instr返回字串第一次出现的索引
length获取字节个数
6.5.1字符串应用
#拼接内容
SELECT CONCAT( 'My' , 's' , 'QL '); #MySQL
#字符串替换
SELECT INSERT('这是一个数据库'3,2'MySql');#结果为这是MySql数据库
#指定内容转换为小写
SELECT LOWER( 'mYsQL ');#mysql
#指定内容转换为大写
SELECT UPPER( 'mysql');#MYSQL
#指定内容截取
SELECT SUBSTRING( 'JavaMysQLOracle' ,5,5);#MySQL

6.6聚合函数

SELECT 聚合函数(列名) FROM 表名;

  • 经验:对多条数据的单列进行统计,返回统计后的一行结果。
  • 注意:聚合函数自动忽略null值,不进行统计
聚合函数说明
SUM()求所有行中单列结果的总和
AVG()平均值
MAX()最大值
MIN()最小值
COUNT()求总行数
单列总和
#统计所有员工每月的工资总和
SELECT sum(salary)
FROM t_employees;
单列平均值
#统计所有员工每月的平均工资
SELECT AVG(salary)
FROM t_employees;
单列最大值
#统计所有员工中月薪最高的工资
SELECT MAX( salary)
FROM t_employees;
单列最小值
#统计所有员工中月薪最低的工资
SELECT MIN(salary)
FROM t_employees;
总行数
#统计员工总数
select count(*)
from t_employees;
#统计有提成的员工人数
select count(commission_pct)
from t_employees;

特点:
1、以上五个分组函数都忽略null值,除了count(*)
2、sum和avg一般用于处理数值型
max、min、count可以处理任何数据类型
3、都可以搭配distinct使用,用于统计去重后的结果
4、count的参数可以支持:
字段、*、(常量值,一般放1)*

​ 建议使用 count(*)

6.7分组查询

select  查询的字段,分组函数  from 表 where 条件 group by  分组的字段

关键字说明
group by分组依据,必须在where之后生效
特点:
1、可以按单个字段分组
2、和分组函数一同查询的字段最好是分组后的字段
3、分组筛选
		     针对的表	    位置		  关键字
分组前筛选:	原始表		group by的前面		where
分组后筛选:	分组后的结果集	group by的后面		having

4、可以按多个字段分组,字段之间用逗号隔开
5、可以支持排序
6having后可以支持别名
6.7.1查询各部门的总人数
#思路:
#1.按照部门编号进行分组(分组依据是department_id)
#2.再针对各部门的人数进行统计(count)
SELECT department_id, COUNT(employee_id)
FROM t_employees
GROUP BY department id;
6.7.2查询各部门的平均工资
#思路:
#1.按照部门编号进行分组(分组依据department_id)
#2.针对每个部门进行平均工资统计(avg) 
SELECT department_id,AVG(salary)
FROM t. employees
GROUP BY department_id
6.7.3查询各个部门、各个岗位的人数
#思路:
#1.按照部门编号进行分组(分组依据department_id) 。
#2.按照岗位名称进行分组(分组依据job_id)。
#3.针对每个部门中的各个岗位进行人数统计(count) 。
SELECT department_id,job_id,COUNT(employee_id)
FROM t_ employees
GROUP BY department_id,job_id;
6.7.4常见问题 #error
#查询各部门id、总人数、first_name
select department_id,count(*),first_name
from t_employees
group by department_id; #error
  • 注:分组查询中,select显示的列只是分组依据列,或者聚合函数列,不能出现其他列.

6.8分组过滤查询

语法:select 列名 from 表名 where 条件 group BY 分组列 having 过滤规则

关键字说明
having 过滤规则过滤规则定义对分组后的数据进行过滤
6.8.1统计部门的最高工资
#统计60、70、90号部门的最高工资
#思路:
#1).确定分组依据(department_id)
#2).对分组后的数据,过滤出部门编号是60、70、90信息
#3).max()函数处理
SELECT department_id , MAX( salary)
FROM t_employees
GROUP BY department_id
HAVING department_id in (60,70,90)
#group确定分组依据department_id
#having过滤出60 70 90部门
#select查看部门编号和max函数。

6.9限定查询(分页查询)

应用场景:

实际的web项目中需要根据用户的需求提交对应的分页查询sql语句
select 字段|表达式,...
from 表
【where 条件】
【group by 分组字段】
【having 条件】
【order by 排序的字段】
limit 起始行,查询行数;
关键字说明
limit offset_start, row_count限定查询结果的起始行和总行数

特点:

1.起始条目索引从0开始
2.limit子句放在查询语句的最后
3.公式:select * fromlimit (page-1*sizePerPage,sizePerPage
假如:
每页显示条目数sizePerPage
要显示的页数 page
6.9.1查询前5行记录
#查询表中前五名员工的所有信息
SELECT * FROM t_employees LIMIT 0,5;
  • 注意:起始行是从0开始,代表了第一行。第二个参数代表的是从指定行开始查询几行
6.9.2查询范围记录
#查询表中从第四条开始,查询10行
SELECT * FROM t_employees LIMIT 3,10;
6.9.3 LIMIT典型应用

分页查询/限定查询:一页显示10条,一共查询3页

#思路:第一页是从0开始,显示10条
select * from limit 0,10;

#第二页是从第10条开始,显示10条
select * from limit 10,10;

#第三页是从20条开始,显示10条
select * from limit 20,10;

经验:在分页应用场景中,起始行是变化的,但是一页显示的条数是不变的

6.10查询总结

6.10.1 SQL语句编写顺序
select 列名 from 表名 where 条件 group by 分组 having 过滤条件 order by 排序列(asc|desc) limit 起始行,总条数
6.10.2 SQL语句执行顺序
1.from:指定数据来源表
2.where:对查询数据做第一次过滤
3.group by:分组
4.having:对分组后的数据第二次过滤
5.select:查询各字段的值
6.order by:排序
7.limit:限定查询结果

6.11子查询(作为条件判断)

select 列名 from 表名 where 条件(子查询结果)

含义:

一条查询语句中又嵌套了另一条完整的 select语句,其中被嵌套的 select语句,称为子查询或内查询
在外面的查询语句,称为主查询或外查询

特点:

1、子查询都放在小括号内
2、子查询可以放在 from后面、 select后面、 where后面、 having后面,但一般放在条件的右侧
3、子查询优先于主查询执行,主查询使用了子查询的执行结果
4、子查询根据查询结果的行数不同分为以下两类:
① 单行子查询
	结果集只有一行
	一般搭配单行操作符使用:>  <  =  < >   > =   < = 
	非法使用子查询的情况:
	a、子查询的结果为一组值
	b、子查询的结果为空
	
② 多行子查询
	结果集有多行
	一般搭配多行操作符使用: anyallinnot in
	in: 属于子查询结果中的任意一个就行
	anyall往往可以用其他查询代替
6.11.1查询年龄大于小明80的学生信息
#1.先查询到 小明80的年龄(一行一列)
select age from student where name="小明80"    age=80
#2.查询年龄大于80的学生信息
select * from student where age>=80
#3.将1.2两条语句整合
select * from student where age>=(select age from student where name="小明80")
  • 注意:将子查询"一行一列"的结果作为外部查询的条件,做第二次查询
  • 子查询得到一行一列的结果才能作为外部查询的等值判断条件或不等值条件判断

6.12子查询(作为枚举查询条件)

select 列名 from 表名 where 列名 in(子查询结果);
6.12.1查询与名为’King’同一部门的员工信息
#思路:
#1.先查询'King’所在的部门编号(多行单列)
SELECT department_id
FROM t_employees
WHERE last_name = 'King' ; //部门编号:80、90

#2.再查询80、90号部门的员工信息
SELECT employee_id , first_name , salary , department_idFROM t_employees
WHERE department_id in ( 80,90 ) ;

#3.SQL:合并
SELECT employee_id , first_name , salary , department_id
FROM t_employees
WHERE department_id in (SELECT department_id cfrom t.employees WHERE last_name = 'King'); #N行一列

  • 将子查询”多行一列“的结果作为外部查询的枚举查询条件,做第二次查询
6.12.2工资高于60部门所有人的信息
#1.查询60部门所有人的工资(多行多列)
SELECT SALARY from t_employees WHERE DEPARTMENT_ID=60;
#2.查询高于60部门所有人的工资的员工信息(高于所有)
select * from t.employees where SALARY > ALL(select SALARY from t.employees WHERE DEPARTMENT_ID=60);
# 查询高于60部门的工资的员工信息(高于部分)
select * from t.employees where SALARY > ANY(select SALARY from t.employees WHERE DEPARTMENT_ID=60);
  • 注意:当子查询结果集形式为多行单列时可以使用ANY或ALL关键字

6.13子查询(作为一张表)

SELECT 列名 FROM(子查询的结果集) WHERE 条件;
6.13.1查询员工表中工资排名前5名的员工信息
#思路:
#1.先对所有员工的薪资进行排序(排序后的临时表)
select employee_id , first_name , salary
from t_employees
order by salary desc

#2.再查询临时表中前5行员工信息
select employee_id , first_name , salary
from(临时表)
limit 0,5;

#SQL:合并
select employee_id , first_name , salary
from (select employee_id , first_name , salary from tmemployees order by salary desc) as temp limit 0,5;
  • 将子查询”多行多列“的结果作为外部查询的一张表,做第二次查询。
  • 注意:子查询作为临时表,为其赋予—个临时表名

6.14合并查询(了解)

SELECT * FROM 表名1 UNION SELECT * FROM 表名2 
SELECT * FROM 表名1 UNION ALL SELECT * FROM 表名2
6.14.1合并两张表的结果(去除重复记录)
#合并两张表的结果,去除重复记录
SELECT * FROM t1 UNION SELECT *FROM t2;
  • 注意:合并结果的两张表,列数必须相同,列的数据类型可以不同
  • union代表去重,union all代表不去重

语法:

select 字段|常量|表达式|函数 【from 表】 【where 条件】 unionallselect 字段|常量|表达式|函数 【from 表】 【where 条件】 unionallselect 字段|常量|表达式|函数 【from 表】 【where 条件】 unionall.....
select 字段|常量|表达式|函数 【from 表】 【where 条件】

6.15多表连接查询

select 列名 from1 连接方式 表2 on 连接条件
笛卡尔乘积:如果连接条件省略或无效则会出现
解决办法:添加上连接条件

一、传统模式下的连接 :等值连接——非等值连接

1.等值连接的结果 = 多个表的交集
2.n表连接,至少需要n-1个连接条件
3.多个表不分主次,没有顺序要求
4.一般为表起别名,提高阅读性和性能

二、sql99语法:通过join关键字实现连接

含义:1999年推出的sql语法
支持:等值连接、非等值连接 (内连接)、外连接、交叉连接
语法:
select 字段/列名/...
from1inner|left outer|right outer|crossjoin2 on  连接条件
【inner|left outer|right outer|crossjoin3 on  连接条件
【where 筛选条件】
【group by 分组字段】
【having 分组后的筛选条件】
【order by 排序的字段或表达式】
好处:语句上,连接条件和筛选条件实现了分离,简洁明了!

三、自连接

案例:查询员工名和直接上级的名称

sql99:

SELECT e.last_name,m.last_name
FROM employees e
JOIN employees m ON e.`manager_id`=m.`employee_id`;

sql92:

SELECT e.last_name,m.last_name
FROM employees e,employees m 
WHERE e.`manager_id`=m.`employee_id`;
6.15.1内连接查询(INNER JOIN ON)
#1.查询所有有部门的员工信息(不包括没有部门的员工)SQL标准
SELECT * FROM t_employees INNER JOIN t_jobs ON t_employees.JOB_ID = t_jobs .JOB_ID
#2.查询所有有部门的员工信息(不包括没有部门的员工) MYsQL
SELECT * FROM t_employees,t_jobs WHERE t_employees.JOB_ID = t.jobs.JOB_ID
  • 经验:在MySql中,第二种方式也可以作为内连接查询,但是不符合SQL标准
  • 而第一种属于SQL标准,与其他关系型数据库通用
6.15.2三表连接查询
#查询所有员工工号、名字、部门名称、部门所在国家ID
SELECT * FROM t_employees e
INNER JOIN t_departments d
on e.department_id = d.department_id
INNER JOIN t_locations l
ON d.location_id = l.location_id
6.15.3左外连接(LEFT JOIN ON)
#查询所有员工信息,以及所对应的部门名称(没有部门的员工,也在查询结果中,部门名称以NULL填充)
SELECT e.employee_id , e.first_name , e.salary , d.department_name 
FROM tmemployees e 
LEFT JOIN t_departments d
ON e.department_id = d.department_id;
  • 注意:左外连接,是以左表为主表,依次向右匹配,匹配到,返回结果
  • 匹配不到,则返回NULL值填充
6.15.4右外连接(RIGHT JOIN ON)
#查询所有部门信息,以及此部门中的所有员工信息(没有员工的部门,也在查询结果中,员工信息以NULL填充)
SELECT e.employee_id,e.first_name,e.salary,d.department_name 
FROM t_employees e
RIGHT JOIN t_departments d
ON e.department_id = d.department_id;
  • 注意:右外连接,是以右表为主表,依次向左匹配,匹配到,返回结果
  • 匹配不到,则返回NULL值填充

七、DML语言的学习

7.1新增(insert)

insert into 表名(1,2,...)values(1,2,...);

特点:

1、字段类型和值类型一致或兼容,而且一一对应
2、可以为空的字段,可以不用插入值,或用null填充
3、不可以为空的字段,必须插入值
4、字段个数和值的个数必须一致
5、字段可以省略,但默认所有字段,并且顺序和表中的存储顺序一致
7.1.1添加一条信息
#添加一条工作岗位信息
INSERT INTO t_jobs(JOB_ID,JOB_TITLE,MIN_SALARY,MAX_SALARY) VALUES('JAVA_Le' ,'JAVA_Lecturer',2500,900);
#添加一条员工信息
INSERT INTO 't_employees '
(ENPLOYE_ID,FIRST_NAME,LAST_NAVIE,EMAIL,PHONE_NUNEER,HIRE_DATE,JOB_ID,SALARY,COMMISSTON_PCT,MANACER_ID,DEPARTMENT_ID)
VALUES
('194','Samuel','McCain','SMCCAIN',650.501.3876',‘1998-07-01',‘SH_CLERK','3200',NLL,'123','50');
  • 注意:表名后的列名和VALUES里的值要一一对应(个数、顺序、类型)

7.2修改(update)

update 表名 set 字段=新值,字段=新值 【where 条件】

修改多表语法:

update1 别名1,2 别名2
set 字段=新值,字段=新值
where 连接条件
and 筛选条件
7.2.1修改一条信息
#修改编号为100的员工的工资为25000
UPDATE t_employees SET SALARY=25000 WHERE ENPLOYEE_ID = '100';
#修改编号为135的员工信息岗位编号为ST_MAN,工资为3500
UPDATE t_employees SET JOB_ID=ST_MAN,SALARY = 3500 WHERE ENPLOYEE_ID ='135';
  • 注意∶SET后多个列名=值,绝大多数情况下都要加WHERE条件,指定修改,否则为整表更新

7.3删除(DELETE)

DELETE FROM 表名 WHERE 条件;

多表的删除:

delete 别名1,别名2
from1 别名1,表2 别名2
where 连接条件
and 筛选条件;
7.3.1删除一条信息(delete)
#删除编号为135的员工
DELETE FROM t_employees WHERE ENPLOYEE_ID='135';
#删除姓Peter,并且名为Hall 的员工
DELETE FROM t_employees WHERE FIRST_NAME ='Peter' AND LAST_NAME='Hall';
  • 注意:删除时,如若不加WHERE条件,删除的是整张表的数据
7.3.2清空整表数据(truncate)
truncate table 表名
#清空t_countries整张表
TRUNCATE TABLE t_countries;

注意:与DELETE不加WHERE删除整张表数据不同,TRUNCATE是把表销毁,再按照原表的格式创建一张新表

两种方式的区别【面试题】

#1.truncate不能加where条件,而delete可以加where条件

#2.truncate的效率高一丢丢

#3.truncate 删除带自增长的列的表后,如果再插入数据,数据从1开始
#delete 删除带自增长列的表后,如果再插入数据,数据从上一次的断点处开始

#4.truncate删除不能回滚,delete删除可以回滚

八、数据表操作

8.1数据类型

mysql支持多种类型,大致可以分为三类:数值、日期/时间和字符串(字符)类型.对于我们约束数据的类型有很大的帮助

8.1.1数值类型
类型大小范围(有符号)范围(无符号)用途
int4字节(-2147483648,2147483647)(0,4294967295)大整数值
double8字节(-1.797E+308,-2.22E-308)(0,2.22E-308,1.797E+308)双精度浮点数值
double(M,D)8个字节,M表示长度,D表示小数位数同上,受M和D的约束double(5,2)-999.99-999.99同上,受M和D的约束双精度浮点数值
declmal(M,D)Declmal(M,D)依赖于M和D的值,M最大值为65依赖于M和D的值,M最大值为65小数值
8.1.2日期类型
类型大小范围格式用途
date31000-01-01/9999-12-31YYYY-MM-DD日期值
time3‘-838:59:59’/‘838:59:59’HH:MM:SS时间值或持续时间
year11901/2155YYYY年份值
datetime81000-01-01 00:00:00/9999-12-31 23:59:59YYYY-MM-DD HH:MM:SS混合日期和时间值
timestamp41970-01-01 00:00:00/2038 结束时间是第2147483647秒北京时间2038-1-19 11:14:07, 格林尼治时间2038年1月19日 凌晨03:14:07YYYYMMDDHHMMSS混合日期和时间值,时间戳
8.1.3字符串类型
类型大小用途
char0-255字符定长字符串char(10)10个字符
varchar0-65535字节变长字符串varchar(10)10个字符
blob(binary large object)0-65535字节二进制形式的长文本数据
text0-65535字节长文本数据
  • CHAR和VARCHAR类型类似,但它们保存和检索的方式不同。它们的最大长度和是否尾部空格被保留等方面也不同。在存储或检索过程中不进行大小写转换。
  • BLOB是一个二进制大对象,可以容纳可变数量的数据。有4种BLOB类型:TINYBLOB、BLOB、MEDIUMBLOB和LONGBLOB。它们只是可容纳值的最大长度不同。

8.2数据表的创建(CREATE)

CREATE TABLE表名(
列名 数据类型[约束],
列名 数据类型[约束],
....
列名 数据类型[约束] #最后一列的末尾不加逗号
) [charset=utf8] #可根据需要指定表的字符编码集
8.2.1创建表
列名数据类型说明
subjectIDint课程编号
subjectNamevarchar(20)课程名称
subjectHoursint课程时长
#依据上述表格创建数据表,并向表中插入3条测试语句
CREATE TABLE subject(
subjectId INT,
subjectName VARCHAR(20),
subjectHours INT
)charset=utf8;
INSERT INTO subject(subjectId,subjectName,subjectHours) VALUES(1,'Java',40);
INSERT INTO subject(subjectId,subjectName,subjectHours) VALUES(2,'WYSQL',20);
INSERT INTO subject(subjectId,subjectName,subjectHours) VALUES(3,'JavaScript',30);

8.3数据表的修改(ALTER)

ALTER TABLE 表名操作;
8.3.1向现有表中添加列
#在课程表基础上添加gradeId列
ALTER TABLE subject ADD gradeid int ;
8.3.2修改表中的列
#修改课程表中课程名称长度为10个字符
ALTER TABLE subject MODIFY subjectName VARCHAR(10) ;
  • 注意:修改表中的某列时,也要写全列的名字,数据类型,约束
8.3.3删除表中的列
#删除课程表中gradeId列
ALTER TABLE subject DROP gradeId ;
  • 注意:删除列时,每次只能删除—列
8.3.4修改列名
#修改课程表中subjectHours列为classHours
ALTER TABLE subject CHANGE subjectHours classHours int ;
  • 注意:修改列名时,在给定列新名称时,要指定列的类型和约束
8.3.5修改表名
#修改课程表的subject 为sub
ALTER TABLE subject rename sub ;

8.4数据表的删除(DROP)

DROP TABLE 表名
8.4.1删除学生表
#删除学生表
DROP TABLE subject ;

九、DDL语言的学习

约束

  • 问题:在往已创建表中新增数据时,可不可以新增两行相同列值得数据?
  • 如果可行,会有什么弊端?

9.1实体完整性约束

表中的一行数据代表一个实体(entity),实体完整性的作用即是标识每一行数据不重复、实体唯一。

9.1.1主键约束

PRIMARY KEY唯一,标识表中的一行数据,此列的值不可重复,且不能为NULL

#为表中适用主键的列添加主键约束
CREATE TABLE subject(
subjectId INT PRIMARY KEY,#课程编号标识每一个课程的编号唯一,且不能为NULL
subjectName VARCHAR(20),
subjectHours INT
)charset=utf8;
INSERT INTO subject(subjectId,subjectName,subjectHours) VALUES(1,'Java',40);
INSERT INTO subject(subjectId,subjectName,subjectHours) VALUES(1,'Java',40);#error 主键1已存在
9.1.2唯一约束

UNIQUE唯一,标识表中的一行数据,不可重复,可以为NULL

#为表中列值不允许重复的列添加唯一约束
CREATE TABLE subject(
subjectId INT PRIMARY KEY,
subjectName VARCHAR(20) UNIQUE#课程名称唯—!
subjectHours INT
)charset=utf8;
INSERT INTO subject(subjectId,subjectName,subjectHours) VALUES(1,'Java',40);
INSERT INTO subject(subjectTd,subjectName,subjectHours) VALUES(2,'Java',40);#error 课程名称已存在
9.1.3自动增长列

AUTO_INCREMENT自动增长,给主键数值列添加自动增长.从1开始,每次加1.不能单独使用,和主键配合。

#为表中主键列添加自动增长,避免忘记主键ID序号
CREATE TABLE subject(
subjectId INT PRINARY KEY AUTO_INCREMENT,#课程编号主键且自动增长,会从1开始根据添加数据的顺序依次加1
subjectName VARCHAR(20 ) UNIQUE,
subjectHours INT
)charset=utf8;
INSERT INTO subject(subjectName,subjectHours) VALUES('Java',40 );#课程编号自动从1增长
INSERT INTO subject(subjectName,subjectHours) VALUES('JavaScript',30);#第二条编号为2

9.2域完整性约束

限制列的单元格的数据正确性。

9.2.1非空约束

NOT NULL非空,此列必须有值。

#课程名称虽然添加了唯一约束,但是有NULL值存在的可能,要避免课程名称为NULL
CREATE TABLE subject(
subjectId INT PRIMARY KEY AUTO_INCREMENT,
subjectName VARCHAR(20) UNIQUE NOT NULL,
subjectHours INT
)charset=utf8;
INSERT INTO subject(subjectName,subjectHours) VALUES(NULL,40);#error,课程名称约束了非空
9.2.2默认值约束

DEFAULT值为列赋予默认值,当新增数据不指定值时,书写DEFAULT,以指定的默认值进行填充。

#当存储课程信息时,若课程时长没有指定值,则以默认课时20填充
CREATE TABLE subject(
subjectId INT PRIMARY KEY AUTO_INCREMENT,
subjectName VARCHAR(20) UNIQUE NOT NULL,
subjectHours INT DEFAULT 20
)charset=utf8;
INSERT INTO subject(subjectName,subjectHours) VALUES('Java',DEFAULT);#课程时长以默认值20填充
9.2.3引用完整性约束
  • 语法:constraint引用名foreign key(列名)references 被引用表名(列名)
  • 详解:FOREIGN KEY引用外部表的某个列的值,新增数据时,约束此列的值必须是引用表中存在的值。
#创建专业表
CREATE TABLE Speciality(
id INT PRIMARY KEY AUTO_INCREMENT,
SpecialName VARCHAR(20) UNIQUE NOT NULL)CHARSET=utf8;
#创建课程表(课程表的SpecialId 引用专业表的id)
CREATE TABLE subject(
subjectId INT PRIMARY KEY AUTO_INCREMENT,
subjectName VARCHAR(20) UNIQUE NOT NULL,
subjectHours INT DEFAULT 20,
specialId INT NOT NULL,
CONSTRAINT fk_subject_specialId FOREIGN KEY(speciald) REFERENCES Speciality(id)#引用专业表里的id作为外键,新增课程信息时,约束课程所属的专业。
)charset=utf8;
#专业表新增数据
INSERT INTO speciality(SpecialName ) VALUES('Java');
INSERT INTO Speciality(SpecialName ) VALUES('C#');
#课程信息表添加数据
INSERT INTO subject(subjectName,subjectHours)VALUES('Java',30,1);#专业id为1,引用的是专业表的Java
INSERT INTO subject(subjectName,subjectHours)VALUES('c#NVC',10,2);#专业id为2,引用的是专业表的C#
  • 注意:当两张表存在引用关系,要执行删除操作,一定要先删除从表(引用表),再删除主表(被引用表)

9.3约束创建整合

创建带有约束的表

9.3.1
列名数据类型约束说明
Gradeidint主键、自动增长班级编号
GradeNamevarchar(20)唯一、非空班级名称
create table Grade(
	GradeId int primary key auto_increment ,
	GradeName varchar(20) unique not null
)charset=UTF8;
列名数据类型约束说明
student_idvarchar(50)主键学号
student_namevarchar(50)非空姓名
sexchar(2)默认填充’男’性别
borndatedate非空生日
phonevarechar(11)电话
Gradeidint非空,外键约束:引用班级表的gradeID班级编号
create table student(
	student_id varchar(50) primary key,
	student_name varchatr(50) not null,
	sex char(2) defaule '男',
	borndate date not null,
	phone varchar(11),
	gradeid int not null,
	constraint fk_studnet_gradeid foreign key(gradeid) references Grade(Geadeid)#引用grade表的gradeID列的值作为外键,插入时约束学生的班级编号必须存在 
);
  • 注意:创建关系表时,一定要先创建主表,再创建从表
  • 删除关系表时,先删除从表,再删除主表.

十、TCL语言的学习

10.1模拟转账

生活当中转账是转账方账户扣钱,收账方账户加钱。我们用数据库操作来模拟现实转账。

10.1.1数据库模拟转账
#A账户转账给B账户1000元。
#A账户减1000元
UPDATE account SET MONEY = MONEY-1000 WHERE id=1 ;
#B账户加1000元
UPDATE account SET MONEY = MONEY+1000 WHERE id=2;
  • 上述代码完成了两个账户之间转账的操作。
10.1.2模拟转账错误
#A账户转账给B账户1000元。
#A账户减1000元
UPDATE account SET MONEY = MONEY-1000 WHERE id=1;#断电、异常、出错...
#B账户加1000元
UPDATE account SET MONEY = MONEY+1000 WHERE id=2;
  • 上述代码在减操作后过程中出现了异常或加钱语句出错,会发现,减钱仍旧是成功的,而加钱失败了!
  • 注意∶每条SQL语句都是一个独立的操作,一个操作执行完对数据库是永久性的影响。

10.2事务的概念

事务是一个原子操作。是一个最小执行单元。可以由一个或多个SQL语句组成,在同一个事务当中,所有的SQL语句都成功执行时,整个事务成功,有一个SQL语句执行失败,整个事务都执行失败。

含义:通过一组逻辑操作单元(一组DML——sql语句),将数据从一种状态切换到另外一种状态

10.3事务的边界

开始:连接到数据库,执行一条DML语句。上一个事务结束后,又输入了一条DML语句,即事务的开始
结束:
1).提交:
a.显示提交:commit;
b.隐式提交:一条创建、删除的语句,正常退出(客户端退出连接);

2).回滚:
a.显示回滚:rollback;
b.隐式回滚︰非正常退出(断电、宕机),执行了创建、删除的语句,但是失败了,会为这个无效的语句执行回滚。

10.4事务的原理

数据库会为每一个客户端都维护一个空间独立的缓存区(回滚段),一个事务中所有的增删改语句的执行结果都会缓存在回滚段中,只有当事务中所有SQL语句均正常结束(commit),才会将回滚段中的数据同步到数据库。否则无论因为哪种原因失败,整个事务将回滚(rollback)。

10.5事务的特性

Atomicity(原子性)
	表示一个事务内的所有操作是一个整体,要么全部成功,要么全部失败 
Consistency(—致性)
	表示一个事务内有一个操作失败时,所有的更改过的数据都必须回滚到修改前状态
elsolation(隔离性)
	事务查看数据操作时数据所处的状态,要么是另一并发事务修改它之前的状态,要么是另一事务修改它之后的状态,事务不会查看中间状态的数据。
Durability(持久性)
	持久性事务完成之后,它对于系统的影响是永久性的。

10.6事务应用

应用环境:基于增删改语句的操作结果(均返回操作后受影响的行数),可通过程序逻辑手动控制事务提交或回滚

10.6.1事务完成转账
#A账户给B账户转账。
#1.开启事务
START TRANSACTION;|set AutoCommit=0;#禁止自动提交set AutoCommit=1;#开启自动提交
#2.事务内数据操作语句
UPDATE ACCOUNT SET MONEY = MONEY-1000 WHERE ID = 1;
UPDATE ACCOUNT SET MONEY = MONEY+1000 WHERE ID = 2;
#3.事务内语句都成功了,执行COMMIT;
COMMIT;
#4 .事务内如果出现错误,执行 ROLLBACK;
ROLLBACK;
  • 注意∶开启事务后,执行的语句均属于当前事务,成功再执行COMMIT,失败要进行ROLLBACK

10.7使用到的关键字

set autocommit=0;#禁止自动提交
start transaction;#开启事物
commit;#提交
rollback;#回滚

savepoint  断点
commit to 断点
rollback to 断点

10.8事务的隔离级别:

10.8.1事务并发问题如何发生?
当多个事务同时操作同一个数据库的相同数据时
10.8.2事务的并发问题有哪些?
脏读:一个事务读取到了另外一个事务未提交的数据
不可重复读:同一个事务中,多次读取到的数据不一致
幻读:一个事务读取数据时,另外一个事务进行更新,导致第一个事务读取到了没有更新的数据
10.8.3如何避免事务的并发问题?
通过设置事务的隔离级别
1READ UNCOMMITTED
2READ COMMITTED 可以避免脏读
3REPEATABLE READ 可以避免脏读、不可重复读和一部分幻读
4SERIALIZABLE可以避免脏读、不可重复读和幻读
10.8.4设置隔离级别:
set session|global  transaction isolation level 隔离级别名;
10.8.5查看隔离级别:
select @@tx_isolation;

十一、权限管理

11.1创建用户

create user 用户名 identified by 密码
11.1.1创建一个用户
#创建一个zhangsan用户
create user 'zhangsan' identified by '123456';

11.2授权

grant all on 数据库.to 用户名
11.2.1用户授权
#将companyDB 下的所有表的权限都赋给 zhangsan
grant all on companyDB.* to 'zhangsan';

11.3撤销权限

revoke all on 数据库.from 用户名;
  • 注意:撤销权限后,账户要重新连接客户端才会生效
11.3.1撤销用户权限
#将zhangsan的companyDB 的权限撤销
revoke all on companyDB.* from 'zhangsan';

11.4删除用户

drop user 用户名
11.4.1删除用户
#删除用户zhangsan
drop user 'zhangsan';

十二、视图的讲解

12.1概念

视图,虚拟表,从一个表或多个表中查询出来的表,作用和真实表一样,包含一系列带有行和列的数据。视图中,用户可以使用 SELECT语句查询数据,也可以使用 INSERTUPDATEDELETE修改记录,视图可以使用户操作方便,并保障数据库系统安全。

12.2视图特点

优点
	简单化,数据所见即所得。
	安全性,用户只能查询或修改他们所能见到得到的数据。
	逻辑独立性,可以屏蔽真实表结构变化带来的影响。
缺点
	性能相对较差,简单的查询也会变得稍显复杂。
	修改不方便,特变是复杂的聚合视图基本无法修改。

12.3视图的创建

CREATE VIEW 视图名 AS 查询数据源表语句;
12.3.1创建视图
#创建t_empInfo的视图,其视图从t_employees表中查询到员工编号、员工姓名、员工邮箱、工资
CREATE VIEW t_empInfo
AS
SELECT EMPLOYEE_ID,FIRST_NAME,LAST_NAME,EMAIL,SALARY from t_employees;
12.3.2使用视图
#查询t_empInfo视图中编号为101的员工信息
SELECT * FROM t_empInfo where employee_id = "101';

12.4视图的修改

方式—: CREATE OR REPLACE VIEW 视图名 AS 查询语句
方式二: ALTER VIEW 视图名 AS 查询语句
12.4.1修改视图
#方式1:如果视图存在则进行修改,反之,进行创建
CREATE OR REPLACE VIEW t_empInfo
As
SELECT ENPLOYEE_ID,FIRST_NANE,LAST_NAME,ENAIL,SALARY,DEPARTMENT_ID from t_employees;
#方式2:直接对已存在的视图进行修改
ALTER VIEW t_empInfo
AS
SELECT ENPLOYEE_ID,FIRST_NAME,LAST_NAME,ENAIL,SALARY from t_employees;

12.5视图的删除

DROP VIEW 视图名
12.5.1删除视图
#删除t_empInfo视图
DROP VIEW t_empInfo;
  • 注意︰删除视图不会影响原表

12.6视图的注意事项

注意:
	视图不会独立存储数据,原表发生改变,视图也发生改变。没有优化任何查询性能。
	如果视图包含以下结构中的一种,则视图不可更新
		聚合函数的结果
		DISTINCT去重后的结果
		GROUP BY分组后的结果
		HAVING筛选过滤后的结果
		uNION、UNIONALL联合后的结果
  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值