洒洒水阿萨阿萨

news2024/11/23 11:14:18

1. 多表查询

多表查询(也叫关联查询, 联结查询): 可以用于检索涉及到多个表的数据.
使用关联查询, 可以将两张或多张表中的数据通过某种关系联系在一起, 从而生成需要的结果集.

前提条件: 这些一起查询的表之间它们之间一定是有关联关系.
# 先熟悉一下三张表:
-- 1. 员工表(11个字段)
mysql> DESC employees;
+----------------+-------------+------+-----+---------+-------+
| Field          | Type        | Null | Key | Default | Extra |
+----------------+-------------+------+-----+---------+-------+
| employee_id    | int         | NO   | PRI | 0       |       | -- 员工id
| first_name     | varchar(20) | YES  |     | NULL    |       | -- 名字
| last_name      | varchar(25) | NO   |     | NULL    |       | -- 姓名
| email          | varchar(25) | NO   | UNI | NULL    |       | -- 邮箱
| phone_number   | varchar(20) | YES  |     | NULL    |       | -- 手机号
| hire_date      | date        | NO   |     | NULL    |       | -- 入职日期
| job_id         | varchar(10) | NO   | MUL | NULL    |       | -- 职位(岗位)id
| salary         | double(8,2) | YES  |     | NULL    |       | -- 工资
| commission_pct | double(2,2) | YES  |     | NULL    |       | -- 佣金比例
| manager_id     | int         | YES  | MUL | NULL    |       | -- 上级id
| department_id  | int         | YES  | MUL | NULL    |       | -- 部门id
+----------------+-------------+------+-----+---------+-------+
11 rows in set (0.01 sec)

-- 2. 部门表(4个字段)
mysql> DESC departments;
+-----------------+-------------+------+-----+---------+-------+
| Field           | Type        | Null | Key | Default | Extra |
+-----------------+-------------+------+-----+---------+-------+
| department_id   | int         | NO   | PRI | 0       |       | -- 部门id
| department_name | varchar(30) | NO   |     | NULL    |       | -- 部门名称
| manager_id      | int         | YES  | MUL | NULL    |       | -- 上级id
| location_id     | int         | YES  | MUL | NULL    |       | -- 地址id
+-----------------+-------------+------+-----+---------+-------+
4 rows in set (0.00 sec)

-- 3. 地址表(6个字段)
mysql> DESC locationS;
+----------------+-------------+------+-----+---------+-------+
| Field          | Type        | Null | Key | Default | Extra |
+----------------+-------------+------+-----+---------+-------+
| location_id    | int         | NO   | PRI | 0       |       | -- 地址id
| street_address | varchar(40) | YES  |     | NULL    |       | -- 街道地址
| postal_code    | varchar(12) | YES  |     | NULL    |       | -- 邮政编码
| city           | varchar(30) | NO   |     | NULL    |       | -- 城市
| state_province | varchar(25) | YES  |     | NULL    |       | -- 行政区
| country_id     | char(2)     | YES  | MUL | NULL    |       | -- 国家id
+----------------+-------------+------+-----+---------+-------+
6 rows in set (0.00 sec)
员工表通过"部门id"关联部门表, 部门表通过"地址id"关联地址表.

image-20231026214926544

1.1 分步骤查询

现在查询名字为'Jack'的工作的城市, 多表查询可以通过一张表一张表进行分步查询(不过, 这种方式可能比较麻烦, 效率也不高).
-- 1. 获取获取jack的部门id:
mysql> SELECT first_name, department_id FROM employees WHERE first_name = 'Jack';
+------------+---------------+
| first_name | department_id |
+------------+---------------+
| Jack       |            80 |
+------------+---------------+
1 row in set (0.03 sec)
-- 2. 通过部门id获取地址id:
mysql> SELECT department_id, location_id FROM departments WHERE department_id = 80;
+---------------+-------------+
| department_id | location_id |
+---------------+-------------+
|            80 |        2500 |
+---------------+-------------+
1 row in set (0.01 sec)
-- 3. 通过地址id在地址表中获取工作的城市:
mysql> SELECT location_id, city FROM locations WHERE location_id = 2500;
+-------------+--------+
| location_id | city   |
+-------------+--------+
|        2500 | Oxford |
+-------------+--------+
1 row in set (0.01 sec)
当使用分步骤查询多张表时, 每次查询只能获取一张表的数据, 然后再通过条件去查询下一张表, 以此类推.
这样的处理方式, 需要进行多次数据库查询操作, 增加了数据库的负担, 降低了查询效率.
此外, 分步骤查询还可能导致数据的冗余传输, 即每次查询都需要将上一次查询的结果集传递给下一次查询, 增加了数据传输的开销.

1.2 交叉连接

1.2.1 隐式交叉连接
隐式的交叉连接(implicit cross join): 是指在查询语句中直接使用逗号连接多个表的查询方式.
这种查询语句将返回所有表的笛卡尔积(有人也称它为笛卡尔积连接),
即将左侧表中的每一行与右侧表中的每一行进行组合, 生成所有可能的组合结果.
例如, 假设有两个表A和B, 它们分别包含两列数据, 如下所示:
表 A:             
列1  |  列2
-----|-----
  1  |  a
  2  |  b
  
表 B:
列1  |  列2
-----|-----
  x  |  10
  y  |  20
  
使用逗号进行隐式的交叉连接查询: 
SELECT 列1, 列2 
FROM A, B;

将返回下列笛卡尔积形式的结果集:
列1  |  列2
-----|-----
  1  |  a
  1  |  10
  1  |  20
  2  |  b
  2  |  10
  2  |  20
  
隐式的交叉连接会产生非常大的结果集, 并且往往不是我们需要的结果.
-- 查询员工的名字及其部门名称(需要查询两张表):
SELECT first_name, department_name FROM employees, departments;
mysql> SELECT first_name, department_name FROM employees, departments;
+-------------+----------------------+
| first_name  | department_name      |
+-------------+----------------------+
| Steven      | Payroll              |
| ...         | ...                  |
| William     | Administration       |
+-------------+----------------------+
2889 rows in set (0.03 sec)  
-- 员工表中有107条数据, 部门表中有27条, 交叉查询后得到: 107 * 27 = 2889条数据.
1.2.2 避免笛卡尔积错误
笛卡尔积的错误会在下面条件下产生:
* 1. 省略多个表的连接条件(或关联条件).
* 2. 连接条件(或关联条件)无效.
* 3. 所有表中的所有行互相连接
为了避免笛卡尔积, 可以在WHERE加入有效的连接条件.

当多个表中具有相同列名时, 需要使用表名前缀来区分不同表中的列名.
在使用带有表名前缀的列名时, 查询语句如下:
SELECT table1.column, table2.column
FROM table1, table2
WHERE table1.column1 = table2.column2;

使用了WHERE子句来指定连接条件, 即table1.column1 = table2.column2.
这个连接条件指定了如何将table1和table2中的数据组合在一起.
注意: 使用隐式连接时, 如果不使用表名前缀指定列名, 则可能会出现名字冲突, 并且sql检查器可能无法确定需要连接哪些列m 从而产生错误.
因此, 使用表名前缀来指定列名是一种很好的习惯.
-- 查询员工名字及其部门名称(设置连接条件):
mysql> SELECT first_name, department_name FROM employees, departments
    -> WHERE employees.department_id = departments.department_id; -- 员工表与部门表中都有有department_id, 在字段前面加上表明.
+-------------+------------------+
| first_name  | department_name  |
+-------------+------------------+
| Jennifer    | Administration   |
| Michael     | Marketing        |
| Pat         | Marketing        |
| Den         | Purchasing       |
| Alexander   | Purchasing       |
| ...         | ...              | -- 省略
| John        | Finance          |
| Ismael      | Finance          |
| Jose Manuel | Finance          |
| Luis        | Finance          |
| Shelley     | Accounting       |
| William     | Accounting       |
+-------------+------------------+
106 rows in set (0.01 sec)

-- 有一个员工的部门id为NULL, 没有分配部门.
mysql> SELECT first_name, department_id FROM employees WHERE department_id <=> NULL;
+------------+---------------+
| first_name | department_id |
+------------+---------------+
| Kimberely  |          NULL |
+------------+---------------+
1 row in set (0.01 sec)
-- 为查询的字段设置表明前缀, 提高可读性: 能够更清楚地知道所引用的列来自于哪个表.
mysql> SELECT employees.first_name, departments.department_name FROM employees, departments
    -> WHERE employees.department_id = departments.department_id;
+-------------+------------------+
| first_name  | department_name  |
+-------------+------------------+
| Jennifer    | Administration   |
| Michael     | Marketing        |
| Pat         | Marketing        |
| Den         | Purchasing       |
| Alexander   | Purchasing       |
| ...         | ...              | -- 省略
| John        | Finance          |
| Ismael      | Finance          |
| Jose Manuel | Finance          |
| Luis        | Finance          |
| Shelley     | Accounting       |
| William     | Accounting       |
+-------------+------------------+
106 rows in set (0.00 sec)
1.2.3 表别名
可以使用AS语句(或者使用空格作为别名分隔符)设置别名, 使用表别名可以让查询语句更易读, 易理解.
表别名可以给每个表指定一个简短的名称, 这样在查询语句中引用这些表时, 可以使用简短的别名代替完整的表名, 使查询语句更简洁明了.
这样的查询语句更容易阅读, 也更容易理解其含义.

注意事项:
* 1. 一旦为表设置了别名, 就应该使用这个别名来引用这个表, 而不能再使用原名, 否则会报错.
* 2. 当表名或列名中包含空格, 特殊字符或与MySQL关键字冲突时, 可以通过使用反引号(`)包裹, 
     这样可以确保MySQL正确解析这些标识符(不能使用单双引号).
-- 为表名设置别名
mysql> SELECT `e mp`.first_name, dept.department_name FROM employees AS `e mp`, departments AS `dept`
    -> WHERE `e mp`.department_id = dept.department_id;
+-------------+------------------+
| first_name  | department_name  |
+-------------+------------------+
| Jennifer    | Administration   |
| Michael     | Marketing        |
| Pat         | Marketing        |
| Den         | Purchasing       |
| Alexander   | Purchasing       |
| ...         | ...              | -- 省略
| John        | Finance          |
| Ismael      | Finance          |
| Jose Manuel | Finance          |
| Luis        | Finance          |
| Shelley     | Accounting       |
| William     | Accounting       |
+-------------+------------------+
106 rows in set (0.00 sec)
如果有n个表实现多表的查询, 则需要至少n-1个连接条件.
-- 查询名字为'Jack'的工作的城市:
mysql> SELECT locs.city FROM employees AS `emp`, departments AS `dept`, locations AS `locs`
WHERE emp.department_id = dept.department_id AND dept.location_id = locs.location_id AND emp.first_name = 'Jack';
+--------+
| city   |
+--------+
| Oxford |
+--------+
1 row in set (0.00 sec)
1.2.4 交叉连接完整格式
交叉连接完整格式: 表与表之间使用关键字CROSS JOIN连接:
SELECT 列1, 列2 
FROM A CROSS JOIN B;
WHERE A.column1 = B.column2;
-- 查询名字为'Jack'的工作的城市:
mysql> SELECT locs.city FROM employees AS `emp` CROSS JOIN departments AS `dept` CROSS JOIN locations AS `locs`
    ->  WHERE emp.department_id = dept.department_id AND dept.location_id = locs.location_id AND emp.first_name = 'Jack';
+--------+
| city   |
+--------+
| Oxford |
+--------+
1 row in set (0.02 sec)

2. 多表查询分类

2.1 等值连接与非等值连接

等值连接和非等值连接是关系型数据库查询中的两种主要连接方式, 它们的主要区别在于连接条件的不同.
* 1. 等值连接(Equi-Join): 在等值连接中, 连接条件是两个表中的列值相等.
     也就是说, 等值连接会根据连接条件从一个表中选取每一行数据, 然后与另一个表中满足相同条件的行进行连接.
     例如, 如果有两个表A和B, 其中一个连接条件为"A.id = B.id", 那么这个连接就是一个等值连接,
     它会将A表中id字段的值与B表中id字段的值相等的行连接起来.
     
* 2. 非等值连接(Non-Equi-Join): 在非等值连接中, 连接条件可以是两个表中的列值不等或者使用其他比较运算符(如<, >, <=, >=等).
     非等值连接会根据连接条件从一个表中选取每一行数据, 然后与另一个表中满足条件的行进行连接.
     例如, 如果有两个表A和B, 其中一个连接条件为"A.salary > B.salary", 那么这个连接就是一个非等值连接,
     它会将A表中salary字段的值大于B表中salary字段的值的行连接起来.

* 等值连接要求连接条件中的列值相等, 而非等值连接则可以使用其他比较运算符进行连接.
-- 等值连接案例: 查询员工名字与员工的部门名称:
mysql> SELECT emp.first_name, dept.department_name FROM employees AS `emp`, departments AS `dept`
    -> WHERE emp.department_id = dept.department_id;
+-------------+------------------+
| first_name  | department_name  |
+-------------+------------------+
| Jennifer    | Administration   |
| Michael     | Marketing        |
| Pat         | Marketing        |
| Den         | Purchasing       |
| Alexander   | Purchasing       |
| Shelli      | Purchasing       |
| Sigal       | Purchasing       |
| ...         | ...              | -- 省略
| Jose Manuel | Finance          |
| Luis        | Finance          |
| Shelley     | Accounting       |
| William     | Accounting       |
+-------------+------------------+
106 rows in set (0.04 sec)

2023-10-28_00005

-- 非等值连接案例
-- 1. 查看一下职务等级表:
mysql> select * from job_grades;
+-------------+------------+-------------+
| grade_level | lowest_sal | highest_sal | -- 最低     最高
+-------------+------------+-------------+
| A           |       1000 |        2999 | -- 1000  ~  2999 工资之间为A级.
| B           |       3000 |        5999 | -- 3000  ~  5999 工资之间为B级.
| C           |       6000 |        9999 | -- 6000  ~  9999 工资之间为C级.
| D           |      10000 |       14999 | -- 10000 ~  14999 工资之间为D级.
| E           |      15000 |       24999 | -- 15000 ~  24999 工资之间为E级.
| F           |      25000 |       40000 | -- 25000 ~  40000 工资之间为F级.
+-------------+------------+-------------+
6 rows in set (0.01 sec)

-- 2. 查询员工的名字, 工资, 职务等级.
mysql> SELECT emp.first_name, emp.salary, jg.grade_level FROM employees AS `emp`, job_grades AS `jg`
 WHERE emp.salary BETWEEN jg.lowest_sal AND jg.highest_sal;
+-------------+----------+-------------+
| first_name  | salary   | grade_level |
+-------------+----------+-------------+
| Steven      | 24000.00 | E           |
| Neena       | 17000.00 | E           |
| Lex         | 17000.00 | E           |
| Alexander   |  9000.00 | C           |
| ...         | ...      | .           |
| Jennifer    |  4400.00 | B           |
| Michael     | 13000.00 | D           |
| Pat         |  6000.00 | C           |
| Susan       |  6500.00 | C           |
| Hermann     | 10000.00 | D           |
| Shelley     | 12000.00 | D           |
| William     |  8300.00 | C           |
+-------------+----------+-------------+
107 rows in set (0.00 sec)

2023-10-29_00003

2.2 自连接与非自连接

自连接和非自连接都是关系型数据库中的连接操作, 但它们连接的表的数量和类型有所不同.
* 1. 自连接: 是指一张表与其自身进行连接, 通过将同一张表复制为两份并对它们进行连接操作, 可以找出表内的相关数据并进行比较.
     自连接通常用于查找存在于同一表中的相关数据, 例如员工与员工的上下级关系, 物品与物品的相似度等.

* 2. 非自连接则是指连接不同的表, 通过将不同表的列进行匹配, 可以从多个表中获取相关联的数据并进行更复杂的查询操作.
     非自连接可以用于执行各种联接操作, 包括内连接, 外连接, 交叉连接等.

总之, 自连接和非自连接都是关系型数据库中的连接操作, 但它们的操作对象和目的有所不同.
-- 自连接案例, 查询员工的管理者名字:  
-- worker和manager本质上是同一张表, 只是用取别名的方式虚拟成两张表以代表不同的意义.
mysql> SELECT worker.first_name AS "员工名字", manager.first_name AS "管理者名字"
    -> FROM employees AS `worker`, employees AS `manager`
    -> WHERE worker.manager_id = manager.employee_id;
+-------------+------------+
| 员工名字    | 管理者名字   |
+-------------+------------+
| Neena       | Steven     |
| Lex         | Steven     |
| Alexander   | Lex        |
| Bruce       | Alexander  |
| David       | Alexander  |
| Valli       | Alexander  |
| ...         | ...        |
| Jennifer    | Neena      |
| Michael     | Steven     |
| Pat         | Michael    |
| Susan       | Neena      |
| Hermann     | Neena      |
| Shelley     | Neena      |
| William     | Shelley    |
+-------------+------------+
106 rows in set (0.00 sec)

2.3 SQL99 多表查询语法

SQL99(也称为SQL:1999)引入了标准的多表查询语法, 以提供更强大和灵活的多表查询功能.
以下是SQL99多表查询的一般语法结构:
SELECT 列名1, 列名2, ...
FROM 表名1
JOIN 表名2 ON 连接条件
[JOIN 表名3 ON 连接条件]
...
WHERE 条件;
这里是每个部分的解释:
- SELECT: 指定要从查询结果中返回的列.
- FROM: 指定要查询的表, 可以指定一个或多个表.
- JOIN: 用于将表连接起来, 可以使用多个JOIN语句实现多个表的连接. 
- ON: 指定连接条件, 用于确定如何连接表.
- WHERE: 可选项, 用于指定额外的过滤条件.

* 关键字 JOIN, INNER JOIN, CROSS JOIN的含义是一样的, 都表示内连接.
-- 查询名字为'Jack'的工作的城市:
mysql> SELECT locs.city 
FROM employees AS `emp` JOIN departments AS `dept` ON  emp.department_id = dept.department_id
JOIN locations AS `locs` ON dept.location_id = locs.location_id 
WHERE emp.first_name = 'Jack';
+--------+
| city   |
+--------+
| Oxford |
+--------+
1 row in set (0.00 sec)

2.4 内连接与外连接

内连接和外连接是数据库中两种主要的连接类型, 它们在多表查询中起着重要的作用.
* 1. 内连接(Inner Join): 也被称为自然连接, 它是最常见的连接类型.
     它基于两个或多个表之间的相等关系, 返回满足连接条件的匹配行.
     内连接只返回符合连接条件的行, 其他不满足条件的行将被排除.

* 2. 外连接则包括左外连接, 右外连接和全外连接.
     1. LEFT JOIN(左连接): 左连接将返回左表中的所有行, 以及符合连接条件的右表中的匹配行.
        如果右表中没有与左表匹配的行, 则返回NULL值.
        左连接常用于需要包含左表中的全部数据, 并根据连接条件关联右表的查询需求.

     2. RIGHT JOIN(右连接): 右连接与左连接相反, 它将返回右表中的所有行, 以及符合连接条件的左表中的匹配行.
        如果左表中没有与右表匹配的行, 则返回NULL值.
        右连接在需要包含右表中的全部数据, 并根据连接条件关联左表的查询需求时使用.

     3. FULL JOIN(全连接): 全连接返回两个表中所有行的组合, 不管是否满足连接条件.
        如果没有匹配的行, 则返回NULL值.
        全连接常用于需要包含两个表中全部数据的查询.

总的来说, 内连接只返回两个表中相关联的数据, 而外连接则返回更全面的数据结果, 包括了没有匹配的行.
在MySQL中, "左表"和"右表"是相对于SQL中使用多表查询时指定的表的位置.
当使用JOIN操作将两个或多个表连接时, 左表是在JOIN操作中使用的第一个表, 而右表是在JOIN操作中使用的第二个表(或后续表).

这个术语通常用于描述不同类型的JOIN操作, 如LEFT JOIN和RIGHT JOIN.
LEFT JOIN将左表作为主表, 并在结果中包含左表的所有记录, 而右表中匹配的记录将按照JOIN条件进行连接.
相反, RIGHT JOIN将右表作为主表, 并在结果中包含右表的所有记录, 同时将左表中匹配的记录进行连接.

总之, 左表和右表是相对于多表查询中使用的表的位置, 用于描述JOIN操作中的表连接顺序和结果.
-- 左连接语法: 
SELECT 字段列表 FROM A表 LEFT OUTER JOIN B表 ON 关联条件 WHERE 等其他子句;
-- 或: 
SELECT 字段列表 FROM A表 LEFT JOIN B表 ON 关联条件 WHERE 等其他子句;
-- 查询所有的员工的名字, id, 部门id, 部门名称, 使用左连接:
mysql> SELECT emp.first_name, emp.employee_id, dept.department_id, dept.department_name
FROM employees AS `emp` LEFT JOIN departments AS `dept`
ON emp.department_id = dept.department_id;
+-------------+-------------+---------------+------------------+
| first_name  | employee_id | department_id | department_name  |
+-------------+-------------+---------------+------------------+
| Steven      |         100 |            90 | Executive        |
| ...         |         ... |            .. | ...              | -- 省略
| Kimberely   |         178 |          NULL | NULL             | -- 如果右表中没有与左表匹配的行, 则返回NULL值.
| ...         |         ... |            .. | ...              | -- 省略
| Hermann     |         204 |            70 | Public Relations |
| Shelley     |         205 |           110 | Accounting       |
| William     |         206 |           110 | Accounting       |
+-------------+-------------+---------------+------------------+
107 rows in set (0.00 sec)
-- 右连接语法: 
SELECT 字段列表 FROM A表 RIGHT OUTER JOIN B表 ON 关联条件 WHERE 等其他子句;
-- 或: 
SELECT 字段列表 FROM A表 RIGHT JOIN B表 ON 关联条件 WHERE 等其他子句;
-- 查询部门表:
mysql> select * from departments;
+---------------+----------------------+------------+-------------+
| department_id | department_name      | manager_id | location_id |
+---------------+----------------------+------------+-------------+
|            10 | Administration       |        200 |        1700 |
|            20 | Marketing            |        201 |        1800 |
|            30 | Purchasing           |        114 |        1700 |
|            40 | Human Resources      |        203 |        2400 |
|            50 | Shipping             |        121 |        1500 |
|            60 | IT                   |        103 |        1400 |
|            70 | Public Relations     |        204 |        2700 |
|            80 | Sales                |        145 |        2500 |
|            90 | Executive            |        100 |        1700 |
|           100 | Finance              |        108 |        1700 |
|           110 | Accounting           |        205 |        1700 |
|           120 | Treasury             |       NULL |        1700 |
|           130 | Corporate Tax        |       NULL |        1700 |
|           140 | Control And Credit   |       NULL |        1700 |
|           150 | Shareholder Services |       NULL |        1700 |
|           160 | Benefits             |       NULL |        1700 |
|           170 | Manufacturing        |       NULL |        1700 |
|           180 | Construction         |       NULL |        1700 |
|           190 | Contracting          |       NULL |        1700 |
|           200 | Operations           |       NULL |        1700 |
|           210 | IT Support           |       NULL |        1700 |
|           220 | NOC                  |       NULL |        1700 |
|           230 | IT Helpdesk          |       NULL |        1700 |
|           240 | Government Sales     |       NULL |        1700 |
|           250 | Retail Sales         |       NULL |        1700 |
|           260 | Recruiting           |       NULL |        1700 |
|           270 | Payroll              |       NULL |        1700 |
+---------------+----------------------+------------+-------------+
27 rows in set (0.00 sec)
-- 对员工的部门id去重(查看员工表中使用了几个部门的信息):
mysql>  SELECT DISTINCT department_id FROM employees;
+---------------+
| department_id |
+---------------+
|          NULL |
|            10 |
|            20 |
|            30 |
|            40 |
|            50 |
|            60 |
|            70 |
|            80 |
|            90 |
|           100 |
|           110 |
+---------------+
12 rows in set (0.00 sec)
部门表中有27个部门的信息, 
员工表中右一个人没有部门, 其他的106人分别在11个部门下工作, 那么部门表中还有16个部门没有员工.
使用右连接后应该有: 106 + 16 = 122 条数据.
106: 是满足"emp.department_id = dept.department_id"的数据.
16:  是没有满足"emp.department_id = dept.department_id"的数据.
-- 查询所有的员工的名字, id, 部门id, 部门名称, 使用右连接:
mysql> SELECT emp.first_name, emp.employee_id, dept.department_id, dept.department_name
FROM employees AS `emp` RIGHT JOIN departments AS `dept`
ON emp.department_id = dept.department_id;
+-------------+-------------+---------------+----------------------+
| first_name  | employee_id | department_id | department_name      |
+-------------+-------------+---------------+----------------------+
| Jennifer    |         200 |            10 | Administration       |
| ...         |         ... |            .. | ...                  | -- 省略
| NULL        |        NULL |           120 | Treasury             |
| NULL        |        NULL |           130 | Corporate Tax        |
| NULL        |        NULL |           140 | Control And Credit   |
| NULL        |        NULL |           150 | Shareholder Services |
| NULL        |        NULL |           160 | Benefits             |
| NULL        |        NULL |           170 | Manufacturing        |
| NULL        |        NULL |           180 | Construction         |
| NULL        |        NULL |           190 | Contracting          |
| NULL        |        NULL |           200 | Operations           |
| NULL        |        NULL |           210 | IT Support           |
| NULL        |        NULL |           220 | NOC                  |
| NULL        |        NULL |           230 | IT Helpdesk          |
| NULL        |        NULL |           240 | Government Sales     |
| NULL        |        NULL |           250 | Retail Sales         |
| NULL        |        NULL |           260 | Recruiting           |
| NULL        |        NULL |           270 | Payroll              |
+-------------+-------------+---------------+----------------------+
122 rows in set (0.02 sec)

2.5 UNION合并语句

UNION关键字: 用于将两个或更多SELECT语句的结果集合并成一个结果集, 它用于在SQL查询中合并多个查询的结果.
当使用UNION时, 每个SELECT语句必须具有相同的列数和相似的数据类型, 因为UNION会将它们的结果合并到一个结果集中.
UNION会自动去重, 即如果两个查询结果中有相同的行, UNION只会保留其中一个.

除了UNION外, 还有UNION ALL, 它与UNION类似, 但不会去重, 即会保留所有查询结果中的行, 包括重复的行.
-- MySQL不支持FULL JOIN, 但是可以用LEFT JOIN UNION RIGHT join代替.
-- 语法如下:
SELECT 字段列表 FROM A表 LEFT JOIN B表 ON 关联条件 WHERE 等其他子句;
UNION [ALL]
SELECT 字段列表 FROM A表 RIGHT JOIN B表 ON 关联条件 WHERE 等其他子句;

-- 注意: 执行UNION ALL语句时所需要的资源比UNION语句少.
-- 如果明确知道合并数据后的结果数据不存在重复数据, 或者不需要去除重复的数据, 则尽量使用UNION ALL语句, 以提高数据查询的效率.
使用全连接后应该有: 1 + 106 + 16 = 123 条数据.
106: 是满足"emp.department_id = dept.department_id"的数据.
17 : 是没有满足"emp.department_id = dept.department_id"的数据(左边有1条不满足, 右边有16条不满足).
-- 模拟全连接并去重:
mysql> SELECT emp.first_name, emp.employee_id, dept.department_id, dept.department_name
FROM employees AS `emp` LEFT JOIN  departments AS `dept`
ON emp.department_id = dept.department_id
UNION 
SELECT emp.first_name, emp.employee_id, dept.department_id, dept.department_name
FROM employees AS `emp` RIGHT JOIN  departments AS `dept`
ON emp.department_id = dept.department_id;
+-------------+-------------+---------------+----------------------+
| first_name  | employee_id | department_id | department_name      |
+-------------+-------------+---------------+----------------------+
| Steven      |         100 |            90 | Executive            |
| ...         |         ... |            .. | ...                  | -- 省略
| Jack        |         177 |            80 | Sales                |
| Kimberely   |         178 |          NULL | NULL                 |
| ...         |         ... |            .. | ...                  | -- 省略
| NULL        |        NULL |           120 | Treasury             |
| NULL        |        NULL |           130 | Corporate Tax        |
| NULL        |        NULL |           140 | Control And Credit   |
| NULL        |        NULL |           150 | Shareholder Services |
| NULL        |        NULL |           160 | Benefits             |
| NULL        |        NULL |           170 | Manufacturing        |
| NULL        |        NULL |           180 | Construction         |
| NULL        |        NULL |           190 | Contracting          |
| NULL        |        NULL |           200 | Operations           |
| NULL        |        NULL |           210 | IT Support           |
| NULL        |        NULL |           220 | NOC                  |
| NULL        |        NULL |           230 | IT Helpdesk          |
| NULL        |        NULL |           240 | Government Sales     |
| NULL        |        NULL |           250 | Retail Sales         |
| NULL        |        NULL |           260 | Recruiting           |
| NULL        |        NULL |           270 | Payroll              |
+-------------+-------------+---------------+----------------------+
123 rows in set (0.01 sec)
-- 模拟全连接不去重(1 + 106 + 106 + 16 = 229):
mysql> SELECT emp.first_name, emp.employee_id, dept.department_id, dept.department_name
FROM employees AS `emp` LEFT JOIN  departments AS `dept`
ON emp.department_id = dept.department_id
UNION ALL
SELECT emp.first_name, emp.employee_id, dept.department_id, dept.department_name
FROM employees AS `emp` RIGHT JOIN  departments AS `dept`
ON emp.department_id = dept.department_id;
+-------------+-------------+---------------+----------------------+
| first_name  | employee_id | department_id | department_name      |
+-------------+-------------+---------------+----------------------+
| Steven      |         100 |            90 | Executive            |
| ...         |         ... |            .. | ...                  |
| NULL        |        NULL |           270 | Payroll              |
+-------------+-------------+---------------+----------------------+
229 rows in set (0.00 sec)

image-20231031190450483

-- 查询部门编号>90或邮箱包含a的员工部门id, 名字, 邮箱:
mysql> SELECT department_id, first_name, email FROM employees
WHERE  department_id > 90 OR email LIKE '%a%';
+---------------+-------------+----------+
| department_id | first_name  | email    |
+---------------+-------------+----------+
|            90 | Neena       | NKOCHHAR |
|            90 | Lex         | LDEHAAN  |
|            60 | Alexander   | AHUNOLD  |
|            .. | ...         | ...      | -- 省略
|            40 | Susan       | SMAVRIS  |
|            70 | Hermann     | HBAER    |
|           110 | Shelley     | SHIGGINS |
|           110 | William     | WGIETZ   |
+---------------+-------------+----------+
67 rows in set (0.00 sec)

-- 使用UNION操作符:
mysql> SELECT department_id, first_name, email FROM employees WHERE department_id > 90
UNION
SELECT department_id, first_name, email FROM employees WHERE email LIKE '%a%';
+---------------+-------------+----------+
| department_id | first_name  | email    |
+---------------+-------------+----------+
|            90 | Neena       | NKOCHHAR |
|            90 | Lex         | LDEHAAN  |
|            60 | Alexander   | AHUNOLD  |
|            .. | ...         | ...      | -- 省略
|            40 | Susan       | SMAVRIS  |
|            70 | Hermann     | HBAER    |
|           110 | Shelley     | SHIGGINS |
|           110 | William     | WGIETZ   |
+---------------+-------------+----------+
67 rows in set (0.00 sec)

2.6 USING连接

自然连接 NATURAL JOIN
同名字段连接 USING JOIN

2.7 连接方式总结

image-20231101063002692

-- 内连接, 返回两个表中匹配的行:
mysql> SELECT employee_id, first_name, department_name
FROM employees AS `EMP`
JOIN departments AS `dept`
ON emp.`department_id` = dept.`department_id`;
+-------------+-------------+------------------+
| employee_id | first_name  | department_name  |
+-------------+-------------+------------------+
|         200 | Jennifer    | Administration   |
|         201 | Michael     | Marketing        |
|         ... | ...         | ...              | -- 省略
|         113 | Luis        | Finance          |
|         205 | Shelley     | Accounting       |
|         206 | William     | Accounting       |
+-------------+-------------+------------------+
106 rows in set (0.00 sec)
-- 左外连接, 返回两个表中匹配的行, 以及左表中没有匹配的行.
mysql> SELECT emp.first_name, emp.employee_id, dept.department_id, dept.department_name
FROM employees AS `emp` LEFT JOIN departments AS `dept`
ON emp.department_id = dept.department_id;
+-------------+-------------+---------------+------------------+
| first_name  | employee_id | department_id | department_name  |
+-------------+-------------+---------------+------------------+
| Steven      |         100 |            90 | Executive        |
| ...         |         ... |            .. | ...              | -- 省略
| Kimberely   |         178 |          NULL | NULL             | -- 如果右表中没有与左表匹配的行, 则返回NULL值.
| ...         |         ... |            .. | ...              | -- 省略
| Hermann     |         204 |            70 | Public Relations |
| Shelley     |         205 |           110 | Accounting       |
| William     |         206 |           110 | Accounting       |
+-------------+-------------+---------------+------------------+
107 rows in set (0.00 sec)
-- 右外连接, 返回两个表中匹配的行, 以及右表中没有匹配的行.
mysql> SELECT emp.first_name, emp.employee_id, dept.department_id, dept.department_name
FROM employees AS `emp` RIGHT JOIN departments AS `dept`
ON emp.department_id = dept.department_id;
+-------------+-------------+---------------+----------------------+
| first_name  | employee_id | department_id | department_name      |
+-------------+-------------+---------------+----------------------+
| Jennifer    |         200 |            10 | Administration       |
| ...         |         ... |            .. | ...                  | -- 省略
| NULL        |        NULL |           120 | Treasury             |
| NULL        |        NULL |           130 | Corporate Tax        |
| NULL        |        NULL |           140 | Control And Credit   |
| NULL        |        NULL |           150 | Shareholder Services |
| NULL        |        NULL |           160 | Benefits             |
| NULL        |        NULL |           170 | Manufacturing        |
| NULL        |        NULL |           180 | Construction         |
| NULL        |        NULL |           190 | Contracting          |
| NULL        |        NULL |           200 | Operations           |
| NULL        |        NULL |           210 | IT Support           |
| NULL        |        NULL |           220 | NOC                  |
| NULL        |        NULL |           230 | IT Helpdesk          |
| NULL        |        NULL |           240 | Government Sales     |
| NULL        |        NULL |           250 | Retail Sales         |
| NULL        |        NULL |           260 | Recruiting           |
| NULL        |        NULL |           270 | Payroll              |
+-------------+-------------+---------------+----------------------+
122 rows in set (0.02 sec)
-- 左差集 A - (A∩B) : 返回左表没有被匹配成功的行.
mysql> SELECT emp.first_name, emp.employee_id, dept.department_id, dept.department_name
FROM employees AS `emp` LEFT JOIN departments AS `dept`
ON emp.department_id = dept.department_id 
WHERE dept.department_id is null;
+------------+-------------+---------------+-----------------+
| first_name | employee_id | department_id | department_name |
+------------+-------------+---------------+-----------------+
| Kimberely  |         178 |          NULL | NULL            |
+------------+-------------+---------------+-----------------+
1 row in set (0.00 sec)
-- 问题: 为什么是 WHERE B.key_column IS NULL; 而不是 WHERE A.key_column IS NULL;
SELECT A.*  
FROM table_A A  
LEFT JOIN table_B B ON A.key_column = B.key_column  
WHERE B.key_column IS NULL; 
SQL查询中, 使用LEFT JOIN来连接table_A和table_B.
这意味着, 获取到 table_A 的所有记录, 并与table_B中匹配的记录进行连接.
如果table_B中没有与table_A中的记录匹配的记录, 那么table_B中的所有列都将为NULL.

因此, 当我们使用WHERE B.key_column IS NULL, 我们实际上是在查找那些在table_B中没有与table_A中的记录匹配的记录.
换句话说, 这些记录存在于table_A中, 但不存在于table_B中, 即 A - (A ∩ B).
 
现在有一个员工的id为null, 那么A.key_column IS NULL得到的结果没有问题(但这并不代表这个方式是正确的).
如果员工的id不是null, 而是其他不存在与B表中的id, 那么那么A.key_column IS NULL得到的结果就是一个空集.

B.key_column IS NULL能保证结果一定是对的, 而A.key_column IS NULL无法保证!
-- 右差集 B - (A∩B) : 返回右表没有被匹配成功的行.
mysql> SELECT emp.first_name, emp.employee_id, dept.department_id, dept.department_name
FROM employees AS `emp` RIGHT JOIN departments AS `dept`
ON emp.department_id = dept.department_id
WHERE emp.department_id IS NULL;
+------------+-------------+---------------+----------------------+
| first_name | employee_id | department_id | department_name      |
+------------+-------------+---------------+----------------------+
| NULL       |        NULL |           120 | Treasury             |
| NULL       |        NULL |           130 | Corporate Tax        |
| NULL       |        NULL |           140 | Control And Credit   |
| NULL       |        NULL |           150 | Shareholder Services |
| NULL       |        NULL |           160 | Benefits             |
| NULL       |        NULL |           170 | Manufacturing        |
| NULL       |        NULL |           180 | Construction         |
| NULL       |        NULL |           190 | Contracting          |
| NULL       |        NULL |           200 | Operations           |
| NULL       |        NULL |           210 | IT Support           |
| NULL       |        NULL |           220 | NOC                  |
| NULL       |        NULL |           230 | IT Helpdesk          |
| NULL       |        NULL |           240 | Government Sales     |
| NULL       |        NULL |           250 | Retail Sales         |
| NULL       |        NULL |           260 | Recruiting           |
| NULL       |        NULL |           270 | Payroll              |
+------------+-------------+---------------+----------------------+
16 rows in set (0.00 sec)
-- 全连接, 返回两个表的所有行.
mysql> SELECT emp.first_name, emp.employee_id, dept.department_id, dept.department_name
FROM employees AS `emp` LEFT JOIN departments AS `dept`
ON emp.department_id = dept.department_id
UNION
SELECT emp.first_name, emp.employee_id, dept.department_id, dept.department_name
FROM employees AS `emp` RIGHT JOIN departments AS `dept`
ON emp.department_id = dept.department_id;
+-------------+-------------+---------------+----------------------+
| first_name  | employee_id | department_id | department_name      |
+-------------+-------------+---------------+----------------------+
| Steven      |         100 |            90 | Executive            |
| ...         |         ... |            .. | ...                  | -- 省略
| Jack        |         177 |            80 | Sales                |
| Kimberely   |         178 |          NULL | NULL                 |
| ...         |         ... |            .. | ...                  | -- 省略
| NULL        |        NULL |           120 | Treasury             |
| NULL        |        NULL |           130 | Corporate Tax        |
| NULL        |        NULL |           140 | Control And Credit   |
| NULL        |        NULL |           150 | Shareholder Services |
| NULL        |        NULL |           160 | Benefits             |
| NULL        |        NULL |           170 | Manufacturing        |
| NULL        |        NULL |           180 | Construction         |
| NULL        |        NULL |           190 | Contracting          |
| NULL        |        NULL |           200 | Operations           |
| NULL        |        NULL |           210 | IT Support           |
| NULL        |        NULL |           220 | NOC                  |
| NULL        |        NULL |           230 | IT Helpdesk          |
| NULL        |        NULL |           240 | Government Sales     |
| NULL        |        NULL |           250 | Retail Sales         |
| NULL        |        NULL |           260 | Recruiting           |
| NULL        |        NULL |           270 | Payroll              |
+-------------+-------------+---------------+----------------------+
123 rows in set (0.01 sec)
-- 差集集合, 返回左差集与右差集的集合,
mysql> SELECT emp.first_name, emp.employee_id, dept.department_id, dept.department_name
FROM employees AS `emp` LEFT JOIN departments AS `dept`
ON emp.department_id = dept.department_id 
WHERE dept.department_id IS NULL
UNION ALL  -- 没有重复的行使用UNION ALL效率更高!
SELECT emp.first_name, emp.employee_id, dept.department_id, dept.department_name
FROM employees AS `emp` RIGHT JOIN departments AS `dept`
ON emp.department_id = dept.department_id
WHERE emp.department_id IS NULL;
+------------+-------------+---------------+----------------------+
| first_name | employee_id | department_id | department_name      |
+------------+-------------+---------------+----------------------+
| Kimberely  |         178 |          NULL | NULL                 |
| NULL       |        NULL |           120 | Treasury             |
| NULL       |        NULL |           130 | Corporate Tax        |
| NULL       |        NULL |           140 | Control And Credit   |
| NULL       |        NULL |           150 | Shareholder Services |
| NULL       |        NULL |           160 | Benefits             |
| NULL       |        NULL |           170 | Manufacturing        |
| NULL       |        NULL |           180 | Construction         |
| NULL       |        NULL |           190 | Contracting          |
| NULL       |        NULL |           200 | Operations           |
| NULL       |        NULL |           210 | IT Support           |
| NULL       |        NULL |           220 | NOC                  |
| NULL       |        NULL |           230 | IT Helpdesk          |
| NULL       |        NULL |           240 | Government Sales     |
| NULL       |        NULL |           250 | Retail Sales         |
| NULL       |        NULL |           260 | Recruiting           |
| NULL       |        NULL |           270 | Payroll              |
+------------+-------------+---------------+----------------------+
17 rows in set (0.00 sec)

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

微信小程序快速备案的通道揭秘方法

随着国家政策的调整&#xff0c;微信小程序备案已变得刻不容缓。传统备案路径较为繁琐&#xff0c;耗时较长&#xff0c;为解决此痛点&#xff0c;今天我们将揭示一个快速备案的新通道。 步骤1&#xff1a;探索智慧助手 打开微信&#xff0c;探索“智慧商家服务助手”公众号。…

阿里云OS系统Alibaba Cloud Linux 3系统的安全更新命令

给客户部署的服务&#xff0c;进入运维阶段&#xff0c;但是经常被客户监测到服务器漏洞&#xff0c;现在整理一下&#xff0c;服务器漏洞问题更新命令步骤。 服务器系统&#xff1a; 阿里云linux服务器&#xff1a;Alibaba Cloud Linux 3 漏洞类型和描述&#xff1a; #3214…

[ASP]校无忧在线考试系统 v3.7

校无忧在线考试系统采用互联网技术,快速搭建在线考试系统平台,全面实现了考试工作的网络化、无纸化、自动化。系统操作简单,题型丰富,广泛用于企事业单位,学校教育培训机构等在线考试,网络考试,在线考核…… 系统主要功能&#xff1a; 1、设置基本考试系统信息(开通/关闭考试等…

听GPT 讲Rust源代码--library/std(12)

题图来自 Decoding Rust: Everything You Need to Know About the Programming Language[1] File: rust/library/std/src/os/watchos/mod.rs 该文件&#xff08;rust/library/std/src/os/watchos/mod.rs&#xff09;的作用是为Rust标准库提供支持WatchOS操作系统的特定功能。 W…

【JVM经典面试题(五十二道)】

文章目录 JVM经典面试题&#xff08;五十二道&#xff09;引言1.什么是JVM 内存管理2.能说一下JVM的内存区域吗&#xff1f;3.说一下JDK1.6、1.7、1.8内存区域的变化&#xff1f;4.为什么使用元空间替代永久代作为方法区的实现&#xff1f;5.对象创建的过程了解吗&#xff1f;6…

这两天公司面了一个字节来的要求月薪23K,明显感觉他背了很多面试题...

最近有朋友去字节面试&#xff0c;面试前后进行了20天左右&#xff0c;包含4轮电话面试、1轮笔试、1轮主管视频面试、1轮hr视频面试。 据他所说&#xff0c;80%的人都会栽在第一轮面试&#xff0c;要不是他面试前做足准备&#xff0c;估计都坚持不完后面几轮面试。 其实&…

k8s-服务网格实战-入门Istio

istio-01.png 背景 终于进入大家都比较感兴趣的服务网格系列了&#xff0c;在前面已经讲解了&#xff1a; 如何部署应用到 kubernetes服务之间如何调用如何通过域名访问我们的服务如何使用 kubernetes 自带的配置 ConfigMap 基本上已经够我们开发一般规模的 web 应用了&#xf…

【克隆方法+深浅拷贝】

文章目录 前言Clonable 接口克隆方法代码的实现 浅拷贝深拷贝总结 前言 Clonable 接口 克隆方法代码的实现 //1.当类要调用克隆方法时&#xff0c;这个类要实现一个Cloneable接口 class Student implements Cloneable{public String name;public int age;public Student(Str…

软件测试/测试开发丨ChatGPT能否成为PPT最佳伴侣

点此获取更多相关资料 简介 PPT 已经渗透到我们的日常工作中&#xff0c;无论是工作汇报、商务报告、学术演讲、培训材料都常常要求编写一个正式的 PPT&#xff0c;协助完成一次汇报或一次演讲。PPT相比于传统文本的就是有布局、图片、动画效果等&#xff0c;可以给到观众更好…

使用IDEA生成JavaDoc文档(IDEA2023)

1、Tool-->Generate JavaDoc 2、配置生成JavaDoc文档 1、选择生成范围&#xff0c;可以根据需要选择单独一个文件或者包&#xff0c;也可以是整个项目 2、输出目录&#xff0c;要把JavaDoc文档生成在哪个文件中&#xff0c;最好新建一个文件夹结束 3、Local&#xff1a;…

云计算的思想、突破、产业实践

文章目录 &#x1f4d5;我是廖志伟&#xff0c;一名Java开发工程师、Java领域优质创作者、CSDN博客专家、51CTO专家博主、阿里云专家博主、清华大学出版社签约作者、产品软文创造者、技术文章评审老师、问卷调查设计师、个人社区创始人、开源项目贡献者。&#x1f30e;跑过十五…

解决爬虫在重定向(Redirect)情况下,URL没有变化的方法

重定向是一种网络服务&#xff0c;它可以实现从一个网页跳转到另一个网页的功能。它把用户请求的网页重定向到一个新的位置&#xff0c;而这个位置可以是更新的网页&#xff0c;或最初请求的网页的不同版本。另外&#xff0c;它还可以用来改变用户流量&#xff0c;当用户请求某…

SpringCloud Alibaba 【四】Openfeign

Openfeign配置与使用 前言介绍openfeign使用openfeign导入依赖启动类正式使用测试结果 前言 在springcloud中消费者项目需要调用提供者项目的接口&#xff0c;一开始用的是RestTemplate中的方法。但是RestTemplate进行远程调用时&#xff0c;直接调用controller层的接口&#…

如何设置OBS虚拟摄像头给钉钉视频会议使用

环境&#xff1a; OBS Studio 29.1.3 Win10 专业版 钉钉7.1.0 问题描述&#xff1a; 如何设置OBS虚拟摄像头给钉钉视频会议使用 解决方案&#xff1a; 1.打开OBS 底下来源这添加视频采集设备 选择OBS虚拟摄像头 2.源那再建一个图像&#xff0c;随便选一张图片 3.点击虚…

基于stm32F4的智能宠物喂食器的设计:LVGL界面、定时喂食喂水通风

宠物喂食器 一、功能设计二、元器件选型三、UI设计四、原理图设计五、源代码设计六、成品展示 实物链接&#xff1a;https://m.tb.cn/h.5iCUX6H?tkPL65WXCEipQ CZ3457 一、功能设计 1、设计一个触摸屏作为人机交互 2、通过触摸屏设置时间定时喂食喂水通风 3、获取当前水槽的…

【CASS精品教程】CASS3D基础知识详解

点击3D图标加载影像数据(支持格式 .osgb 、.obj 、.xml 、.s3c),这里以 .xml 数据格式为例: 下面开始讲操作。 CASS 平台下二、三维窗口为联动操作,当鼠标指针位于三维窗口时: 缩放窗口—— 滑动鼠标滚轮平移窗口—— 按住鼠标滚轮并拖动鼠标旋转视角—— 按住鼠标左键…

【入门Flink】- 04Flink部署模式和运行模式【偏概念】

部署模式 在一些应用场景中&#xff0c;对于集群资源分配和占用的方式&#xff0c;可能会有特定的需求。Flink为各种场景提供了不同的部署模式&#xff0c;主要有以下三种&#xff1a;会话模式&#xff08;Session Mode&#xff09;、单作业模式&#xff08;Per-Job Mode&…

使用ssl_certificate_by_lua指令动态加载证书

1、下载 OpenResty - 下载 根据自己系统选择下载&#xff0c;我的是64位 2、解压到目录 3、启动openresty 进入解压后的目录&#xff0c;执行nginx.exe 浏览器输入 http://localhost 查看是否正常。显示以下画面就表示没有问题。 接下来可以开始准备动态安装证书 4、使用o…

QT+SQLite数据库配置和使用

一、简介 1.1 SQLite&#xff08;sql&#xff09;是一款开源轻量级的数据库软件&#xff0c;不需要server&#xff0c;可以集成在其他软件中&#xff0c;非常适合嵌入式系统。Qt5以上版本可以直接使用SQLite&#xff08;Qt自带驱动&#xff09;。 二、下载和配置 2.1 SQLite下载…

SpringBoot3.* 集成又拍云上传组件

集成使用 添加Maven依赖 <!--又拍云--> <dependency><groupId>com.upyun</groupId><artifactId>java-sdk</artifactId><version>4.2.3</version> </dependency>代码编写 PostMapping("/common/upload") pu…