Day11:关于MySQL的数据查询——子查询和联合查询
前言:先创建一个练习的数据库和数据
1.创建数据库并创建数据表的基本结构
-- 创建数据库
CREATE DATABASE subquery_union_simple;
USE subquery_union_simple;
-- 1. 员工表
CREATE TABLE employees (
emp_id INT PRIMARY KEY AUTO_INCREMENT,
emp_name VARCHAR(50) NOT NULL,
salary DECIMAL(10,2) NOT NULL,
hire_date DATE NOT NULL,
dept VARCHAR(50) NOT NULL
);
-- 2. 客户表
CREATE TABLE customers (
customer_id INT PRIMARY KEY AUTO_INCREMENT,
customer_name VARCHAR(50) NOT NULL,
city VARCHAR(50) NOT NULL,
credit_rating VARCHAR(20) NOT NULL
);
-- 3. 订单表
CREATE TABLE orders (
order_id INT PRIMARY KEY AUTO_INCREMENT,
customer_id INT,
emp_id INT,
order_date DATE NOT NULL,
amount DECIMAL(10,2) NOT NULL,
FOREIGN KEY (customer_id) REFERENCES customers(customer_id),
FOREIGN KEY (emp_id) REFERENCES employees(emp_id)
);
2.导入实例数据
-- 员工数据
INSERT INTO employees (emp_name, salary, hire_date, dept) VALUES
('张三', 8000.00, '2020-01-15', '销售部'),
('李四', 7500.00, '2021-03-20', '销售部'),
('王五', 9000.00, '2019-05-10', '技术部'),
('赵六', 8500.00, '2020-07-01', '技术部'),
('钱七', 7000.00, '2021-09-01', '财务部');
-- 客户数据
INSERT INTO customers (customer_name, city, credit_rating) VALUES
('客户A', '北京', '优秀'),
('客户B', '上海', '良好'),
('客户C', '广州', '一般'),
('客户D', '深圳', '优秀'),
('客户E', '杭州', '良好'),
('客户F', '成都', '一般');
-- 订单数据
INSERT INTO orders (customer_id, emp_id, order_date, amount) VALUES
(1, 1, '2023-01-05', 15000.00),
(2, 1, '2023-02-10', 8000.00),
(3, 2, '2023-03-15', 12000.00),
(1, 3, '2023-04-20', 25000.00),
(4, 4, '2023-05-25', 18000.00),
(5, 5, '2023-06-30', 30000.00),
(2, 1, '2023-07-05', 9000.00),
(6, NULL, '2023-08-10', 6000.00); -- 未分配员工的订单
一、子查询(嵌套查询)
子查询的主要用途是在执行某个查询的过程中使用另一个查询的结果,即在WHERE子句中包含了另一个SELECT语句,这种将一个查询嵌套在另一个查询的WHERE子句中的查询称为子查询,也称为嵌套查询。
1.结果为单个值
子查询结果为单个值时,条件中可以使用“=”“>”“<”“<=”“>=”“!=”“<>”等比较运算符。
查询工资高于平均工资的员工
SELECT emp_name, salary
FROM employees
WHERE salary > AVG(salary);
mysql> SELECT emp_name, salary
-> FROM employees
-> WHERE salary > AVG(salary);
ERROR 1111 (HY000): Invalid use of group function
由于WHERE子句中不可以使用聚合函数
SELECT emp_name, salary
FROM employees
WHERE salary > (SELECT AVG(salary) FROM employees);
mysql> SELECT emp_name, salary
-> FROM employees
-> WHERE salary > (SELECT AVG(salary) FROM employees);
+----------+---------+
| emp_name | salary |
+----------+---------+
| 王五 | 9000.00 |
| 赵六 | 8500.00 |
+----------+---------+
2 rows in set (0.05 sec)
2.结果为多个值的集合
子查询结果有多个值时,可以使用ANY、SOME、ALL、IN等运算符。
查询信用评级为"优秀"的客户的所有订单
SELECT * FROM orders
WHERE customer_id IN (
SELECT customer_id FROM customers
WHERE credit_rating = '优秀'
);
mysql> SELECT * FROM orders
-> WHERE customer_id IN (
-> SELECT customer_id FROM customers
-> WHERE credit_rating = '优秀'
-> );
+----------+-------------+--------+------------+----------+
| order_id | customer_id | emp_id | order_date | amount |
+----------+-------------+--------+------------+----------+
| 1 | 1 | 1 | 2023-01-05 | 15000.00 |
| 4 | 1 | 3 | 2023-04-20 | 25000.00 |
| 5 | 4 | 4 | 2023-05-25 | 18000.00 |
+----------+-------------+--------+------------+----------+
3 rows in set (0.05 sec)
3.EXISTS子查询
EXISTS用于测试子查询的结果是否为空,如果结果不为空,则返回TRUE;否则返回FALSE。
查询有订单的客户
SELECT customer_name
FROM customers c
WHERE EXISTS (
SELECT 1 FROM orders
WHERE customer_id = c.customer_id
);
mysql> SELECT customer_name
-> FROM customers c
-> WHERE EXISTS (
-> SELECT 1 FROM orders
-> WHERE customer_id = c.customer_id
-> );
+---------------+
| customer_name |
+---------------+
| 客户A |
| 客户B |
| 客户C |
| 客户D |
| 客户E |
| 客户F |
+---------------+
6 rows in set (0.00 sec)
二、联合查询
联合查询是将两个查询结果集合并为一个查询结果集,使用关键字UNION。
SELECT 语句1
UNION [ ALL | DISTINCT ]
SELECT 语句2;
1.UNION运算符可以将前后两个SELECT语句的查询结果进行合并,生成一个数据集。
2.联合查询时默认选项为DISTINCT,表示查询结果集中消除了重复行,所有的记录都是唯一的;若选项为ALL,表示查询结果集中包含查询出的所有记录行。
3.联合查询中的两个SELECT语句必须具有相同的字段列数目、且各字段列具有相同的数据类型。
合并员工和客户名称
SELECT emp_name AS name, '员工' AS type FROM employees
UNION
SELECT customer_name, '客户' FROM customers;
mysql> SELECT emp_name AS name, '员工' AS type FROM employees
-> UNION
-> SELECT customer_name, '客户' FROM customers;
+-------+------+
| name | type |
+-------+------+
| 张三 | 员工 |
| 李四 | 员工 |
| 王五 | 员工 |
| 赵六 | 员工 |
| 钱七 | 员工 |
| 客户A | 客户 |
| 客户B | 客户 |
| 客户C | 客户 |
| 客户D | 客户 |
| 客户E | 客户 |
| 客户F | 客户 |
+-------+------+
11 rows in set (0.05 sec)
合并所有城市信息(员工所在部门和客户所在城市)
SELECT dept AS location, '部门' AS type FROM employees
UNION ALL
SELECT city, '城市' FROM customers;
mysql> SELECT dept AS location, '部门' AS type FROM employees
-> UNION ALL
-> SELECT city, '城市' FROM customers;
+----------+------+
| location | type |
+----------+------+
| 销售部 | 部门 |
| 销售部 | 部门 |
| 技术部 | 部门 |
| 技术部 | 部门 |
| 财务部 | 部门 |
| 北京 | 城市 |
| 上海 | 城市 |
| 广州 | 城市 |
| 深圳 | 城市 |
| 杭州 | 城市 |
| 成都 | 城市 |
+----------+------+
11 rows in set (0.00 sec)
创建销售活动报表(联合查询)
将销售部门的员工薪资数据与销售部门处理的订单金额数据合并成一个结果集,
并按类别和数值降序排列。
查询分为两部分:
第一部分从员工表选取销售部门员工的ID、姓名、薪资,并标记为"员工薪资"类别;
第二部分通过关联订单、客户和员工表,获取销售部门员工处理的订单ID、客户名称、订单金额,并标记为"订单金额"类别。
UNION ALL操作符将这两个结果集合并而不去重,最终结果按类别分组,并在每个类别内按金额/薪资从高到低排序,便于比较销售部门员工的薪资水平和他们产生的订单业绩
SELECT
emp_id AS id,
emp_name AS name,
salary AS value,
'员工薪资' AS category
FROM employees
WHERE dept = '销售部'
UNION ALL
SELECT
o.order_id,
c.customer_name,
o.amount,
'订单金额'
FROM orders o
JOIN customers c ON o.customer_id = c.customer_id
JOIN employees e ON o.emp_id = e.emp_id
WHERE e.dept = '销售部'
ORDER BY category, value DESC;
mysql> SELECT
-> emp_id AS id,
-> emp_name AS name,
-> salary AS value,
-> '员工薪资' AS category
-> FROM employees
-> WHERE dept = '销售部'
-> UNION ALL
-> SELECT
-> o.order_id,
-> c.customer_name,
-> o.amount,
-> '订单金额'
-> FROM orders o
-> JOIN customers c ON o.customer_id = c.customer_id
-> JOIN employees e ON o.emp_id = e.emp_id
-> WHERE e.dept = '销售部'
-> ORDER BY category, value DESC;
+----+-------+----------+----------+
| id | name | value | category |
+----+-------+----------+----------+
| 1 | 客户A | 15000.00 | 订单金额 |
| 3 | 客户C | 12000.00 | 订单金额 |
| 7 | 客户B | 9000.00 | 订单金额 |
| 2 | 客户B | 8000.00 | 订单金额 |
| 1 | 张三 | 8000.00 | 员工薪资 |
| 2 | 李四 | 7500.00 | 员工薪资 |
+----+-------+----------+----------+
6 rows in set (0.05 sec)