表:Prices
+---------------+---------+
| Column Name | Type |
+---------------+---------+
| product_id | int |
| start_date | date |
| end_date | date |
| price | int |
+---------------+---------+
(product_id,start_date,end_date) 是 prices 表的主键(具有唯一值的列的组合)。
prices 表的每一行表示的是某个产品在一段时期内的价格。
每个产品的对应时间段是不会重叠的,这也意味着同一个产品的价格时段不会出现交叉。
表:UnitsSold
+---------------+---------+
| Column Name | Type |
+---------------+---------+
| product_id | int |
| purchase_date | date |
| units | int |
+---------------+---------+
该表可能包含重复数据。
该表的每一行表示的是每种产品的出售日期,单位和产品 id。
编写解决方案以查找每种产品的平均售价。average_price
应该 四舍五入到小数点后两位。
返回结果表 无顺序要求 。
结果格式如下例所示。
示例 1:
输入:
Prices table:
+------------+------------+------------+--------+
| product_id | start_date | end_date | price |
+------------+------------+------------+--------+
| 1 | 2019-02-17 | 2019-02-28 | 5 |
| 1 | 2019-03-01 | 2019-03-22 | 20 |
| 2 | 2019-02-01 | 2019-02-20 | 15 |
| 2 | 2019-02-21 | 2019-03-31 | 30 |
+------------+------------+------------+--------+
UnitsSold table:
+------------+---------------+-------+
| product_id | purchase_date | units |
+------------+---------------+-------+
| 1 | 2019-02-25 | 100 |
| 1 | 2019-03-01 | 15 |
| 2 | 2019-02-10 | 200 |
| 2 | 2019-03-22 | 30 |
+------------+---------------+-------+
输出:
+------------+---------------+
| product_id | average_price |
+------------+---------------+
| 1 | 6.96 |
| 2 | 16.96 |
+------------+---------------+
解释:
平均售价 = 产品总价 / 销售的产品数量。
产品 1 的平均售价 = ((100 * 5)+(15 * 20) )/ 115 = 6.96
产品 2 的平均售价 = ((200 * 15)+(30 * 30) )/ 230 = 16.96
# Write your MySQL query statement below
# 方法一
# select p.product_id, ifnull(round(sum(p.price * u.units) / sum(u.units),2),0) as average_price
# from Prices as p
# left join UnitsSold as u
# on p.product_id = u.product_id
# where datediff(u.purchase_date,p.start_date) >= 0 and datediff(p.end_date , u.purchase_date) >= 0 or u.purchase_date is null
# group by p.product_id;
# 方法二
SELECT
product_id,
IFNULL(Round(SUM(sales) / SUM(units), 2), 0) AS average_price
FROM (
SELECT
Prices.product_id AS product_id,
Prices.price * UnitsSold.units AS sales,
UnitsSold.units AS units
FROM Prices
LEFT JOIN UnitsSold ON Prices.product_id = UnitsSold.product_id
AND (UnitsSold.purchase_date BETWEEN Prices.start_date AND Prices.end_date)
) T
GROUP BY product_id
between and
BETWEEN
和 AND
结合可以用于各种类型的列,不仅限于数字和日期。它们也适用于其他数据类型,比如字符串、时间戳等。
除了数字和日期之外,你可以在以下情况下使用 BETWEEN
和 AND
:
字符串列:
可以用于按字母顺序筛选出位于两个字符串之间的数据。
SELECT *
FROM your_table
WHERE string_column BETWEEN 'A' AND 'F';
这将返回字符串列中以字母 A 到 F 范围内的数据。
时间戳列:
适用于包含时间信息的列,可以按时间范围进行筛选。
SELECT *
FROM your_table
WHERE timestamp_column BETWEEN 'start_timestamp' AND 'end_timestamp';
这将返回时间戳列中在指定范围内的数据。
其它数值列:
适用于任何数字类型的列,可以用于筛选特定范围内的数字。
SELECT *
FROM your_table
WHERE numeric_column BETWEEN 100 AND 500;
这将返回数值列中在 100 到 500 之间的数据。
总的来说,BETWEEN
和 AND
在 MySQL 中对于任何可比较的数据类型都可以使用,只要你需要根据某种范围来筛选数据。
当涉及不同数据类型时,以下是使用 BETWEEN
和 AND
进行筛选的示例:
假设有一个名为 products
的表,其中包含产品名称的列为 product_name
。要选择产品名称以字母 ‘A’ 到 ‘F’ 开头的产品,可以这样写:
SELECT *
FROM products
WHERE product_name BETWEEN 'A' AND 'F';
这将返回产品名称以字母 ‘A’ 到 ‘F’ 开头的所有产品。
假设有一个名为 logs
的表,其中包含时间戳列 log_timestamp
。要选择日期在 2023 年 1 月 1 日到 2023 年 12 月 31 日之间的日志记录,可以这样写:
SELECT *
FROM logs
WHERE log_timestamp BETWEEN '2023-01-01 00:00:00' AND '2023-12-31 23:59:59';
这将返回在指定日期范围内的日志记录。
假设有一个名为 prices
的表,其中包含产品价格的列为 product_price
。要选择价格在 100 到 500 之间的产品,可以这样写:
SELECT *
FROM prices
WHERE product_price BETWEEN 100 AND 500;
这将返回价格在 100 到 500 之间的所有产品。
这些示例展示了如何使用 BETWEEN
和 AND
条件来对不同类型的列进行范围筛选。无论是字符串、日期、时间戳还是数值,BETWEEN
和 AND
运算符都能用于准确地选择特定范围内的数据。
项目表 Project
:
+-------------+---------+
| Column Name | Type |
+-------------+---------+
| project_id | int |
| employee_id | int |
+-------------+---------+
主键为 (project_id, employee_id)。
employee_id 是员工表 Employee 表的外键。
员工表 Employee
:
+------------------+---------+
| Column Name | Type |
+------------------+---------+
| employee_id | int |
| name | varchar |
| experience_years | int |
+------------------+---------+
主键是 employee_id。
请写一个 SQL 语句,查询每一个项目中员工的 平均 工作年限,精确到小数点后两位。
查询结果的格式如下:
Project 表:
+-------------+-------------+
| project_id | employee_id |
+-------------+-------------+
| 1 | 1 |
| 1 | 2 |
| 1 | 3 |
| 2 | 1 |
| 2 | 4 |
+-------------+-------------+
Employee 表:
+-------------+--------+------------------+
| employee_id | name | experience_years |
+-------------+--------+------------------+
| 1 | Khaled | 3 |
| 2 | Ali | 2 |
| 3 | John | 1 |
| 4 | Doe | 2 |
+-------------+--------+------------------+
Result 表:
+-------------+---------------+
| project_id | average_years |
+-------------+---------------+
| 1 | 2.00 |
| 2 | 2.50 |
+-------------+---------------+
第一个项目中,员工的平均工作年限是 (3 + 2 + 1) / 3 = 2.00;第二个项目中,员工的平均工作年限是 (3 + 2) / 2 = 2.50
# Write your MySQL query statement below
select p.project_id, round(sum(e.experience_years)/count(*),2 )as average_years
from Project as p
left join Employee as e
on p.employee_id = e.employee_id
where e.experience_years is not null
group by p.project_id
在 MySQL 中,IF
函数可以接受三个参数。IF
函数的语法如下:
IF(expr, true_value, false_value)
其中:
expr
是要评估的条件表达式或逻辑条件。true_value
是如果条件为真时返回的值。false_value
是如果条件为假时返回的值。IF
函数根据 expr
的评估结果返回 true_value
或 false_value
中的一个。
举个例子,假设有一个表 employees
包含了员工的工资信息,我们想要创建一个查询,如果工资大于 3000,则将其标记为高薪水,否则标记为低薪水。可以使用 IF
函数来实现:
SELECT employee_name, IF(salary > 3000, '高薪水', '低薪水') AS salary_status
FROM employees;
这将返回一个结果集,其中包含员工名字和一个表示薪水状态的列,如果工资大于 3000 则显示为 '高薪水'
,否则显示为 '低薪水'
。
IF
函数在 MySQL 中可以接受三个参数,并且是一个很常用的函数,用于在查询中根据条件返回不同的值。
HAVING
关键字在 SQL 中通常与 GROUP BY
子句一起使用,用于筛选聚合函数操作后的结果。
在 SQL 查询中,HAVING
用于过滤由 GROUP BY
子句创建的组,并且允许你筛选这些组的聚合数据。它在与 GROUP BY
一起使用时,可以针对聚合值(如 COUNT、SUM、AVG 等)进行过滤。
语法结构如下:
SELECT column_name(s), aggregate_function(column_name)
FROM table_name
WHERE condition
GROUP BY column_name(s)
HAVING condition;
在这个语法中:
column_name(s)
是要检索的列名或表达式。aggregate_function
是应用于列的聚合函数,如 COUNT、SUM、AVG 等。table_name
是表名。condition
是筛选条件,可以是对行进行筛选的 WHERE
子句,以及对分组进行筛选的 HAVING
子句。GROUP BY
用于按照指定的列对结果进行分组。HAVING
用于过滤分组后的结果。举个例子,假设有一个名为 orders
的表,其中包含客户ID customer_id
和订单总金额 total_amount
。如果想要找出总订单金额超过 1000 的客户:
SELECT customer_id, SUM(total_amount) AS total_spent
FROM orders
GROUP BY customer_id
HAVING SUM(total_amount) > 1000;
这个查询将按照客户ID分组订单,然后使用 HAVING
子句筛选出总订单金额大于 1000 的客户。
总的来说,HAVING
关键字允许你在聚合操作后对分组的结果进行条件筛选,而 WHERE
关键字则用于对单行进行筛选。
在 MySQL 中,编写 SQL 查询时,关键字的一般顺序是:
这是一种常见的 SQL 查询语句关键字顺序,但并不是严格规定的顺序。在实际使用中,有时你可以根据需求调整关键字的顺序,只要保持语法的正确性和逻辑的清晰性。
例如,JOIN
子句可能会在 FROM
子句之后出现,ORDER BY
可能在 GROUP BY
或 HAVING
之前,这取决于你查询的逻辑结构和需要表达的条件。
这里是一个简单的查询的基本顺序:
SELECT column_name(s)
FROM table_name
JOIN other_table ON conditions
WHERE conditions
GROUP BY column_name(s)
HAVING conditions
ORDER BY column_name(s)
LIMIT number;
这只是一种常用的顺序示例。在实际的 SQL 查询中,你可以根据需要调整关键字的顺序,以便更清晰地表达查询的意图。
用户表: Users
+-------------+---------+
| Column Name | Type |
+-------------+---------+
| user_id | int |
| user_name | varchar |
+-------------+---------+
user_id 是该表的主键(具有唯一值的列)。
该表中的每行包括用户 ID 和用户名。
注册表: Register
+-------------+---------+
| Column Name | Type |
+-------------+---------+
| contest_id | int |
| user_id | int |
+-------------+---------+
(contest_id, user_id) 是该表的主键(具有唯一值的列的组合)。
该表中的每行包含用户的 ID 和他们注册的赛事。
编写解决方案统计出各赛事的用户注册百分率,保留两位小数。
返回的结果表按 percentage
的 降序 排序,若相同则按 contest_id
的 升序 排序。
返回结果如下示例所示。
示例 1:
输入:
Users 表:
+---------+-----------+
| user_id | user_name |
+---------+-----------+
| 6 | Alice |
| 2 | Bob |
| 7 | Alex |
+---------+-----------+
Register 表:
+------------+---------+
| contest_id | user_id |
+------------+---------+
| 215 | 6 |
| 209 | 2 |
| 208 | 2 |
| 210 | 6 |
| 208 | 6 |
| 209 | 7 |
| 209 | 6 |
| 215 | 7 |
| 208 | 7 |
| 210 | 2 |
| 207 | 2 |
| 210 | 7 |
+------------+---------+
输出:
+------------+------------+
| contest_id | percentage |
+------------+------------+
| 208 | 100.0 |
| 209 | 100.0 |
| 210 | 100.0 |
| 215 | 66.67 |
| 207 | 33.33 |
+------------+------------+
解释:
所有用户都注册了 208、209 和 210 赛事,因此这些赛事的注册率为 100% ,我们按 contest_id 的降序排序加入结果表中。
Alice 和 Alex 注册了 215 赛事,注册率为 ((2/3) * 100) = 66.67%
Bob 注册了 207 赛事,注册率为 ((1/3) * 100) = 33.33%
select r.contest_id, round(count(u.user_id) / (select count(*) from Users) * 100,2) as percentage
from Register as r
left join Users as u
on r.user_id = u.user_id
group by contest_id
order by percentage desc , r.contest_id asc;
在 MySQL 中,嵌套查询是指一个查询语句嵌套在另一个查询语句的内部。嵌套查询也被称为子查询,可以用于在查询中使用另一个查询的结果。
下面是使用嵌套查询的一些示例:
WHERE
子句中使用子查询假设我们有两个表:students
和 grades
,我们想查找分数大于 80 分的学生名单。我们可以使用子查询来实现:
SELECT student_name
FROM students
WHERE student_id IN (
SELECT student_id
FROM grades
WHERE score > 80
);
这个查询中的子查询选择了分数大于 80 的学生ID,并将其作为条件传递给外部查询,从而获取了分数大于 80 分的学生名单。
FROM
子句中使用子查询有时可以在 FROM
子句中使用子查询,以创建临时的虚拟表进行进一步的操作。例如,我们想要统计每个部门的平均工资:
SELECT department, AVG(salary) AS avg_salary
FROM (
SELECT e.employee_id, e.department, s.salary
FROM employees e
JOIN salaries s ON e.employee_id = s.employee_id
) AS emp_salary
GROUP BY department;
在这个例子中,子查询用作一个内部的临时表,它从 employees
和 salaries
表中选择了所需的列,然后外部查询对这个虚拟表进行了分组并计算了每个部门的平均工资。
SELECT
子句中使用子查询有时也可以在 SELECT
子句中使用子查询,用来获取额外的信息或计算。例如,查询每个部门中工资最高的员工:
SELECT department,
(SELECT employee_name
FROM employees
WHERE employee_id = (
SELECT employee_id
FROM salaries
WHERE department = e.department
ORDER BY salary DESC
LIMIT 1
)
) AS highest_paid_employee
FROM employees e
GROUP BY department;
这个查询中的子查询嵌套在 SELECT
子句中,用来查找每个部门中工资最高的员工名字。
嵌套查询在 MySQL 中是一种强大的工具,可以根据需要在查询中结合不同的条件、函数和逻辑来使用,以实现更复杂的查询需求。