数据库SQLite(1)

SQL 查询

1 限定查询:

// 查询
SELECT job,sal*15 + 200*12 + 200*12 + 300*4 From emp;
// 去重查询
// 使用DISTINCT 进行去除重复内容
SELECT DISTINCT job FROM emp;
  1. 查询基本工资小于1600的全部雇员信息
SELECT * FROM emp WHERE sal<1600;
  1. 查询姓名是SMITH的雇员信息

字符串需要使用一对单引号或双引号包裹。

SELECT * FROM emp WHERE ename=='SMITH';
  1. 查询所有职位不是销售人员的信息
SELECT * FROM emp WHERE job!='SALESMAN';

【练习】查询工资范围在1200-1500之间的雇员信息。

SELECT * FROM emp WHERE sal BETWEEN 1200 AND 1500;

2 基数范围运算:

​ 基数范围运算使用关键字IN,可以提供几个数据,只要有一个数据匹配,结果就可以匹配。

【例子】查询出雇员编号为7369,7566,7839,8899(不存在)的雇员信息。

SELECT * FROM emp WHERE empno IN (7369,7566,7839,8899);
// 不是这几个编号的
SELECT * FROM emp WHERE empno NOT IN (7369,7566,7839,8899);

3 模糊查询

SELECT * FROM emp WHERE ename LIKE 'A%';

使用两个通配符配合LIKE关键字使用:

_

匹配任意一个字符

%

匹配任意多个(0,1,2,...,n)字符

【例子】

  1. 查询所有姓名包含A字母的雇员信息。
SELECT * FROM emp WHERE ename LIKE '%A%';
  1. 查询姓名是A开头的雇员信息。
SELECT * FROM emp WHERE ename LIKE 'A%';

【练习】

  1. 查询姓名的第二个字母是A的雇员信息。
SELECT * FROM emp WHERE ename LIKE '_A%'
  1. 查询姓名最后一个字母是S的雇员信息。
SELECT * FROM emp WHERE ename LIKE '%S';

4 空信息

NULL 判断需要使用`IS关键字 --IN`关键词也不适合NULL

为空: IS NULL

不为空: IS NOT NULL NOT IS NULL

// 佣金为NULL
SELECT * FROM emp WHERE comm IS NULL;
// 佣金不为NULL -- 两种方式
SELECT * FROM emp WHERE comm IS NOT NULL;
SELECT * FROM emp WHERE NOT comm IS NULL;

5 逻辑运算

AND OR NOT

// 1. 查询出工资范围不在1200~1300(闭区间)之间的员工信息。
SELECT * FROM emp WHERE sal NOT BETWEEN 1200 AND 1300;
// 2. 查询出10部门的经理信息。
SELECT * FROM emp WHERE job = 'MANAGER' AND deptno = 10;
// 3. 查询出工资高于3000,或者职位是柜员的全部雇员信息。
SELECT * FROM emp WHERE sal > 3000 OR job = 'CLERK';
// 4. 查询出所有职位不是柜员的信息
SELECT * FROM emp WHERE NOT job = 'CLERK';

6 查询顺序

ORDER BY

指定结果按照顺序,如果指定数据相同,可以继续指定数据

升序:ASC

降序:DESC

【例子】查询所有雇员的信息,按照工资从高到低排序。

SELECT * FROM emp ORDER BY sal DESC;

【例子】查询所有雇员的信息,按照工资从高到低排序,如果工资相同,则按照雇佣日期从早到晚排序。

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

作业

【Day1作业】

  1. 选择部门30的所有员

  2. 列出所有柜员(CLERK)的姓名、编号和部门编号。

  3. 列出佣金高于薪金30%的员工姓名、职位和收入(薪金+佣金);

  4. 找出部门30中所有经理和部门20中所有柜员的详细资料。

  5. 找出部门30中所有经理、部门20中所有柜员以及既不是经理又不是柜员并且薪金大于等于2000的员工的详细资料。

  6. 收取佣金的工作有哪些?

  7. 找出不收取佣金或佣金低于100的员工。

  8. 显示不带有A的员工的姓名

  9. 显示姓名字段的任何位置包含E的所有员工的详细资料,显示的结果按照基本工资从高到低排序,如果基本工资相同则按照雇佣时间从早到晚排序,如果雇佣的日期相同,则按照职位的字母顺序排序。

  10. 显示非经理员工的姓名、编号、部门编号和总收入INCOME(薪金+佣金),按照总收入从高到低排序;如果总收入相同,按照薪金从高到低排序;如果薪金相同,按照部门号从小到大排序。

SELECT * FROM emp WHERE deptno == 30;

SELECT ename,empno,deptno   FROM emp WHERE job == 'CLERK';

SELECT ename,job,sal + comm 收入 FROM emp WHERE comm >= sal * 0.3;

SELECT * FROM emp WHERE deptno == 30 AND job == 'MANAGER' OR deptno == 20 AND job =='CLERK';

SELECT * FROM emp WHERE deptno == 30 AND job == 'MANAGER' OR deptno == 20 AND job =='CLERK' OR job NOT IN ('MANAGER','CLERK') AND sal >= 2000;

SELECT * FROM emp WHERE comm IS NOT NULL;

SELECT * FROM emp WHERE comm IS NULL OR comm <= 100;

SELECT * FROM emp WHERE NOT ename LIKE '%A%';

SELECT * FROM emp WHERE ename LIKE '%E%' ORDER BY sal DESC , hiredate ASC,ename ASC;

SELECT ename,empno,deptno,sal + COALESCE(comm, 0) INCOME FROM emp WHERE job != 'MANAGER' ORDER BY sal + COALESCE(comm, 0) DESC,sal DESC,deptno ASC;

7 分页查询 :

LIMIT 表示查询结果数量

OFFSET 表示丢弃前几条数据

【例子】

  1. 查询前五个雇员的信息。
SELECT * FROM emp LIMIT 5;

函数

1 大小写转换

输入参数:字符串数据或字符串类型列

函数名称:UPPER(大写)、LOWER(小写)

返回值:全大写或小写的字符串

【例子】使用SQL语句,把'Hello World'分别转换为全大写和全小写。

SELECT UPPER('Hello World'),LOWER('Hello World');

查询姓名职位,并输出为小写

SELECT LOWER (ename),LOWER (job)FROM emp;

2 字符串长度

输入参数:字符串数据或字符串类型列

函数名称:LENGTH

返回值:字符串的长度,一个整数

【例子】计算'Hello World'的长度。

SELECT LENGTH('Hello World');

3 字符串截取

输入参数1:字符串数据或字符串类型列

输入参数2:截取起始点

[输入参数3]:截取的长度,此参数不传递表示截取到最后

函数名称:SUBSTR

返回值:截取的子字符串

【例子】从'Hello World'中截取'World'

SELECT SUBSTR('Hello World',7,5);

数据库中序号从1开始,而不是从0开始。

4 数字函数

四舍五入

输入参数1:要处理的数字或数字类型列

[输入参数2]:保留几位小数,如果不传递表示保留整数位

函数名称:ROUND

返回值:四舍五入后的数字

【例子】对123.456进行四舍五入,要求保留2位小数。

SELECT ROUND(123.456,2);
其他函数

​ ● 求模 MOD

​ ● 绝对值 ABS

5 日期和时间计算

如果单独处理日期,使用DATE函数,如果单独处理时间使用TIME函数,如果同时处理日期和时间使用DATETIME函数。

​ 有了日期和时间就可以单独提取日期、时间。

【例子】只显示每个雇员雇佣的日期,不显示时间。

SELECT DATE(hiredate) FROM emp;

【例子】只显示每个雇员雇佣的时间,不显示日期。

SELECT TIME(hiredate) FROM emp;
获取本地日期时间
SELECT DATETIME ('now','localtime');
儒略日

传入数据:指定日期,当前日期用 ==now==

输入参数:指定的日期,当前日期使用'now'

​ 函数名称:JULIANDAY

​ 返回值:指定日期到儒略日的天数(公元前4713年1月1日)

【例子】今天到儒略日的天数。

SELECT JULIANDAY('now');

【例子】求出每个雇员雇佣的姓名和年数。

SELECT ename,(JULIANDAY('now')-JULIANDAY(hiredate))/365 FROM emp;
时间格式化

image-20241217141309935

输入参数1:替换符,字符串类型

输入参数2:要提取数据的日期时间

函数名称:STRFTIME

返回值:格式化后的数据,==类型为字符串==

【例子】查询所有在上半年雇佣的雇员信息。

SELECT * FROM emp
WHERE STRFTIME('%m',hiredate)<='06';
  1. 查询1981年雇佣的雇员信息。
SELECT * FROM emp WHERE STRFTIME('%Y',hiredate)=='1981';
  1. 查询冬天(11-2)雇佣的雇员信息。
SELECT * FROM empWHERE STRFTIME('%m',hiredate) BETWEEN  "11" AND "12"OR STRFTIME('%m',hiredate) BETWEEN  "01" AND "02";

注意:转换完成的数据为字符串类型,比较时应该与字符串进行对比

6 空值函数

输入参数1:可能为空的数据列

​ 输入参数2:替换值

​ 函数名称:IFNULL

​ 返回值:如果输入参数1为空,返回值为输入参数2;如果输入参数1不为空,返回值为输入参数1

​ 【练习】计算佣金500以下的雇员信息,NULL算作500以下。

SELECT * FROM  emp WHERE IFNULL(comm,0) < 500;

7 统计函数

SUM 求和

AVG 平均值

COUNT 计数

MAX 最大值

MIN 最小值

统计函数的主要用途是与后面要学习的GROUP BY子句联动。

【例子】统计公司雇员人数、支付的总薪金、平均薪金、最高薪金和最低工资。

SELECT COUNT(*),SUM(sal),AVG(sal),MAX(sal),MIN(sal) FROM emp;

【思考】COUNT(*)、COUNT(字段)、COUNT(DISTINCT 字段)的区别。

-- emp表中有几条数据
SELECT COUNT(*) FROM emp;
-- 有几个人有领导
SELECT COUNT(mgr) FROM emp;

-- 有几个人拿佣金
SELECT COUNT(comm) FROM emp;
-- 公司领导有几个人
SELECT COUNT(DISTINCT mgr) FROM emp;

多表查询

1 笛卡尔积

当查询多个表会产生笛卡尔积,类似于两表相乘,因此,需要进行where条件限定,进行过滤冗余数据

【例子】查询每个雇员的编号、姓名、职位、工资、部门编号、部门名称、位置。

分析:

  1. 确定FROM子句

emp表:empno,ename,job,sal,deptno

dept表:dname,loc

FROM emp e,dept d
  1. 确定WHERE子句

之前如果查询所有人就不使用WHERE筛选了,多表查询会产生笛卡尔积,需要用WHERE筛选行数。

WHERE e.deptno=d.deptno
  1. 确定SELECT子句
SELECT empno,ename,job,sal,e.deptno,dname,loc
  1. 确定ORDER BY子句
  2. 确定其他子句
  3. 拼接
SELECT empno,ename,job,sal,e.deptno,dname,loc
FROM emp e,dept d
WHERE e.deptno=d.deptno;

2 内连接 和外连接

内连接

之前的多表查询都是内连接,并且都使用的是SQL89标准,除此之外还有SQL99标准。

【例子】查询所有雇员的姓名和部门名称。

-- SQL89
SELECT ename,dname FROM emp e,dept d WHERE e.deptno=d.deptno;
-- SQL99
SELECT ename,dname
FROM emp e JOIN dept d ON e.deptno=d.deptno;

建议后续使用99标准,原因有二:

● SQL99标准可以解放WHERE子句,简化WHERE逻辑

● SQL99标准更适合后续学习的外连接

外连接

​ 数据库中通常把外连接分为2-3种:

● 左外连接:SQLite支持的外连接

● 右外连接:左外连接相反的方向,SQLite不支持,但是与左外连接可以互相转换

● 全外连接:左外连接+右外连接

3 其他连接

交叉连接

==CROSS==

​ 生成笛卡尔积不消除也被称为“交叉连接”。

​ 下面两种写法等效:

SELECT * FROM emp,dept;
SELECT * FROM emp CROSS JOIN dept;
自然连接

==NATURAL==

多表查询时,自动找到相关联字段,并消除笛卡尔积

SELECT * FROM emp  NATURAL JOIN dept;

相当于

SELECT *FROM emp e JOIN dept d ON e.deptno = d.deptno;

但是,不是万能的

非等式关系不会生效

USING 关键字

==USING==

使用USING 关键字消除笛卡尔积,这种方法基于内链接

SELECT * FROM emp JOIN dept USING(deptno);
-- 相当于
SELECT * FROM emp e JOIN dept d ON e.deptno = d.deptno;
交集与并集

image-20241218163208233

如图,交叉部分(橙色)为交集, 全部颜色为并集

UNION

操作表示公共区域叠加一次的==并集==。

【例子】查询公司部门20和基本工资高于1500的雇员信息。

-- 部门20的雇员信息
SELECT * FROM emp WHERE deptno=20;
-- 基本工资高于1500的雇员信息
SELECT * FROM emp WHERE sal>1500;
-- 使用UNION并集操作
SELECT * FROM emp WHERE deptno=20
UNION
SELECT * FROM emp WHERE sal>1500;
UNION ALL

相比 UNION ,交集部分会被叠加为两次

INTERSECT

==INTERSECT==

显示交集

【例子】查询公司部门20且工资高于1500的雇员信息。

SELECT * FROM emp WHERE deptno=20
INTERSECT
SELECT * FROM emp WHERE sal>1500;

分组统计

1 分组依据

对数据进行分组的前提是某些数据之间具有相同的特征,例如emp表中,job、deptno、mgr这三个字段存在不同雇员的重复。

​ 按照job分组,可以分为销售组、经理组......

​ 按照deptno分组,可以分为10部门组、20部门组......

​ 按照mgr分组,可以分为7902组、7698组.......

​ 理论上按照ename这种字段分组是可行的,但是每个组中只有一条记录,这样分组没有意义。

2 分组查询

基本语法

==SELECT== 列名, 聚合函数(列名)
==FROM== 表名
==WHERE== 条件
==GROUP BY== 分组列
==HAVING== 分组过滤条件
==ORDER BY== 排序列;

【例子】按照职位分组,统计出每个职位的平均工资、最高工资、最低工资和人数。

分析:通常分组查询都会伴随分组统计,即分组后使用统计函数(SUM、AVG、COUNT、MAX、MIN)。因为分组后不存在个体了,对于群体而言,无法使用单一的字段(例如ename)进行描述(销售组的员工姓名是什么????)。

  1. 确定FROM子句
FROM emp
  1. 确定WHERE子句

​ 所有人都要参与统计,不需要使用WHERE

  1. 确定GROUP BY子句
GROUP BY job
  1. 确定SELECT子句
-- 分组之后可以使用分组字段提升分组后查询数据可读性
SELECT job,AVG(sal),MAX(sal),MIN(sal),COUNT(empno)
  1. 确定ORDER BY子句
  2. 确定其他子句
  3. 拼接
SELECT job,AVG(sal),MAX(sal),MIN(sal),COUNT(empno)
FROM emp
GROUP BY job;

3分组筛选

不能在WHERE子句中使用统计函数

对于分组之后的筛选,应该通过HAVING子句实现。

【总结】WHERE与HAVING的区别:

1 WHERE在分组之前使用,是对个体进行筛选;HAVING是在分组之后使用,是对群体进行筛选。

2 WHERE不支持统计函数,HAVING支持统计函数。

3 WHERE可以单独使用,HAVING必须结合GROUP BY使用。

例子

--1.查询出所有雇员和其领导的姓名和年薪。
SELECT e.ename , e.sal*12 + IFNULL(e.comm,0)*12,m.ename , m.sal*12 + IFNULL(m.comm,0)*12 FROM emp e LEFT JOIN emp m ON  e.mgr = m.empno;

--2.列出至少有四个员工的所有部门编号、部门名称、部门人数
SELECT e.deptno,dname,COUNT(*) FROM dept d JOIN emp e ON d.deptno = e.deptno GROUP BY d.deptno HAVING COUNT(*)>=4; 

--3.列出雇佣日期早于其领导的所有员工的编号,姓名,部门名称,领导名称。
SELECT e.empno,e.ename,d.dname,m.ename FROM emp e JOIN emp m ON e.mgr = m.empno JOIN dept d ON e.deptno = d.deptno WHERE e.hiredate < m.hiredate;

--4.列出所有部门名称和这些部门的员工信息(人数、平均工资、平均服务年限、最高最低工资),同时列出那些没有员工的部门。
SELECT dname,AVG(sal + IFNULL(comm,0)),AVG((JULIANDAY('now') - JULIANDAY(hiredate))/365),MIN(sal + IFNULL(comm,0)) FROM dept d  LEFT JOIN emp e ON e.deptno = d.deptno GROUP BY e.deptno;

--5.列出最低工资大于1500的职位名称和以及此职位的人数。
SELECT job,COUNT(*) FROM emp GROUP BY job HAVING MIN(sal) > 1500; 

--6.列出各个部门的CLERK(柜员)的最低薪金。
SELECT d.dname, MIN(sal) FROM emp e JOIN dept d ON e.deptno = d.deptno WHERE job = 'CLERK' GROUP BY e.deptno;

--7.求出部门名称中带‘S’字符的部门员工的工资合计和部门的人数
SELECT dname , SUM(sal + IFNULL(comm,0)) ,COUNT(e.empno) FROM dept d LEFT JOIN emp e ON e.deptno = d.deptno WHERE dname LIKE '%S%' GROUP BY deptno; 

子查询

​ 子查询指的是在一个查询中嵌入若干个小的查询,也可以理解为查询的嵌套。

​ 绝大多数情况下,子查询具有以下规律:

● 子查询返回的是单行单列(一个数据本身):HAVING WHERE

img

● 子查询返回单行多列(一条数据):WHERE

img

● 子查询返回多行多列(一个表):FROM

img

WHERE 子查询

WHERE的功能主要是控制数据行,对个体数据进行筛选与过滤,WHERE子查询的返回结果一般都是:

● 单行单列

● 多行单列

● 单行多列

返回单行单列

【例子】统计出所有高于公司平均工资的雇员信息。

分析:

​ 第一步,计算公司的平均工资。

SELECT AVG(sal) FROM emp;

img
返回单行单列数据。

​ 第二步,统计公司工资高于2073.2142的雇员信息。

SELECT * FROM emp WHERE sal>2073.2142;

​ 第三步,把第一步的结果嵌套。

SELECT * FROM emp WHERE sal>(SELECT AVG(sal) FROM emp);

img

【练习】统计出公司最早雇佣的雇员信息,要求使用子查询完成。

select * 
from emp 
where hiredate=(select min(hiredate) from emp);
返回单行多列

【例子】显示出公司雇佣最早且工资最低的雇员信息。

分析:

​ 第一步,查询出公司最早雇佣的日期和最低的工资。

SELECT MIN(hiredate) FROM emp;
SELECT MIN(sal) FROM emp;

​ 第二步,把上面的结果嵌套在WHERE子句中进行查询。

SELECT * FROM emp 
WHERE hiredate=(SELECT MIN(hiredate) FROM emp)
AND sal=(SELECT MIN(sal) FROM emp);

img

【例子】查询与SCOTT工资且职位相同的雇员信息。

SELECT * FROM emp 
WHERE sal=(SELECT sal FROM emp WHERE ename='SCOTT')
AND job=(SELECT job FROM emp WHERE ename='SCOTT')
AND ename<>'SCOTT';

img

返回多行单列

​ 一个简单的多行单列返回结果如下:

img

相当于提供了同一个字段的多个数据,可以配合之前的IN操作。

【例子】显示工资跟各个经理相同的雇员信息(包含各个经理)。

分析:

第一步,查询各个经理的工资:

SELECT sal FROM emp WHERE job='MANAGER';

第二步,把上一步的内容作为WHERE的子查询,配合IN进行操作。

SELECT * FROM emp 
WHERE sal IN(SELECT sal FROM emp WHERE job='MANAGER');

img

需要注意的是,IN不能处理NULL。

【练习】查询与每个分析师部门相同的雇员信息,要求不包含分析师。

SELECT *
FROM emp
WHERE deptno IN (SELECT deptno FROM emp WHERE job='ANALYST')
AND job !='ANALYST';
HAVING 子查询

如果有HAVING子查询,一定有GROUP BY子句,并且会有统计函数。

HAVING子查询几乎只支持返回单行单列的结果。

【例子】查询出高于公司平均工资的部门编号和这些部门的平均工资。

分析:

​ 第一步,计算公司的平均工资。

SELECT AVG(sal) FROM emp;

​ 第二步,使用HAVING子查询。

SELECT deptno,AVG(sal)
FROM emp
GROUP BY deptno
HAVING AVG(sal)>(SELECT AVG(sal) FROM emp);

img

【思考】查询出平均工资最低的职位信息,此职位的人数,此职位的平均工资。

法一:使用本节方法——HAVING子查询

​ 第一步,查询每个职位的平均工资。

SELECT AVG(sal) FROM emp GROUP BY job;

img

​ 第二步,查询平均最低的职位的平均工资。

SELECT MIN(avs)
FROM (SELECT AVG(sal) avs FROM emp GROUP BY job);

img

​ 第三步,使用HAVING子查询。

SELECT job,COUNT(empno),AVG(sal)
FROM emp
GROUP BY job
HAVING AVG(sal)=(SELECT MIN(avs)
FROM (SELECT AVG(sal) avs FROM emp GROUP BY job));

img

​ 虽然上面的做法比较麻烦,但是通用性好。

法二:可以使用之前的LIMIT关键字解决。

​ 第一步,查询所有职位的人数和平均工资。

SELECT job,COUNT(empno),AVG(sal)
FROM emp
GROUP BY job;

​ 第二步,按照平均工资升序。

SELECT job,COUNT(empno),AVG(sal)
FROM emp
GROUP BY job
ORDER BY AVG(sal) ASC;

img

​ 第三步,直接使用LIMIT保留第一条记录。

SELECT job,COUNT(empno),AVG(sal)
FROM emp
GROUP BY job
ORDER BY AVG(sal) ASC
LIMIT 1;

img

SELECT 子查询

【例子】显示所有雇员的姓名、职位、部门名称和部门位置。

分析:正常的解法是使用多表查询,关联deptno字段。

SELECT ename,job,dname,loc
FROM emp e LEFT JOIN dept d ON e.deptno=d.deptno;

本节使用子查询实现,不是问题的最优解。

SELECT e.ename,e.job,
(SELECT dname FROM dept WHERE deptno=e.deptno),
(SELECT loc FROM dept WHERE deptno=e.deptno)
FROM emp e;

img

​ 上面的做法可以训练思维,实际使用中没有任何价值。

FROM 子查询

​ FROM子句的主要功能是确定查询的数据表来源,表是一种行列的集合,因此FROM子句出现的子查询结果通常是多行多列的。

【例子】查询出每个部门的编号、名称、位置、部门人数和平均工资。

法一:直接使用多表查询。

SELECT d.deptno,dname,loc,COUNT(empno),AVG(sal)
FROM dept d LEFT JOIN emp e ON d.deptno=e.deptno
GROUP BY dname;

emp表中有14条数据,dept表中有4条数据,直接使用多表查询,虽然消除了笛卡尔积,但是中间的过程仍然生成笛卡尔积,数据量=14x4=56

法二:使用子查询

​ 第一步,只考虑emp表,原题删减为:

查询出每个部门的编号、名称、位置、部门人数和平均工资。

SELECT deptno,COUNT(empno),AVG(sal)
FROM emp
GROUP BY deptno;

img
temp表

​ 第二步,把第一步查询的结果看做是一张表——temp表,使用temp表与dept表进行多表查询,完成原题的功能。

​ 查询出每个部门的编号、名称、位置、部门人数和平均工资。

SELECT d.deptno,dname,loc,temp.部门人数,temp.平均工资
FROM dept d LEFT JOIN temp ON d.deptno=temp.deptno;

​ 上面的语句无法运行,把temp的子查询套入。

SELECT d.deptno,dname,loc,temp.ce,temp.av
FROM dept d LEFT JOIN (
    SELECT deptno,COUNT(empno) ce,AVG(sal) av
    FROM emp
    GROUP BY deptno) temp 
ON d.deptno=temp.deptno;

img

​ 第一步子查询,针对emp单表查询,最多操作14条数据,返回了3条数据(最多4条)。

​ 第二步子查询(内嵌的子查询与dept表关联),也生成笛卡尔积,最多4*4=16条数据。

​ 两步总计操作数据量=14+16=30条

​ 性能差距54/30=1.8倍。

​ 以上数据量比较小,如果emp表和dept表的数据量扩充100倍,性能差距会更大(自己可以算算)。

总结

​ 除了FROM子查询以外,其他的子查询:

​ ● 训练思维

​ ● 提升编写效率

​ FROM子查询除了具有以上两个优势外,还可以提升执行效率。

上一篇
下一篇