MK
摩柯社区 - 一个极简的技术知识社区
AI 面试

MySQL SELECT语句基础与数据检索技巧

2023-01-234.2k 阅读

MySQL SELECT 语句基础

简单的 SELECT 语句

在 MySQL 中,SELECT 语句是用于从数据库中检索数据的核心语句。其最基本的形式如下:

SELECT column1, column2
FROM table_name;

这里,column1column2 是你想要从 table_name 表中获取的列名。例如,假设有一个名为 employees 的表,其中包含 first_namelast_namesalary 列,要获取员工的名字和姓氏,可以这样写:

SELECT first_name, last_name
FROM employees;

如果想要获取表中的所有列,可以使用通配符 *

SELECT *
FROM employees;

不过,在实际生产环境中,除非确实需要所有列,否则不建议使用 *,因为这可能会检索出不必要的数据,增加网络传输和处理的开销。

选择特定条件的数据

通过 WHERE 子句,可以筛选出满足特定条件的数据。WHERE 子句紧跟在 FROM 子句之后,语法如下:

SELECT column1, column2
FROM table_name
WHERE condition;

condition 是一个返回布尔值(TRUEFALSENULL)的表达式。例如,要从 employees 表中获取工资大于 5000 的员工的名字和姓氏:

SELECT first_name, last_name
FROM employees
WHERE salary > 5000;

WHERE 子句中可以使用多种运算符,包括比较运算符(如 ><=!=>=<=)、逻辑运算符(ANDORNOT)等。比如,要获取工资在 5000 到 10000 之间的员工:

SELECT first_name, last_name
FROM employees
WHERE salary >= 5000 AND salary <= 10000;

对结果进行排序

ORDER BY 子句用于对 SELECT 语句返回的结果进行排序。它可以按照一个或多个列进行升序(ASC)或降序(DESC)排序。语法如下:

SELECT column1, column2
FROM table_name
ORDER BY column1 [ASC|DESC], column2 [ASC|DESC];

例如,要按照工资降序获取员工的名字、姓氏和工资:

SELECT first_name, last_name, salary
FROM employees
ORDER BY salary DESC;

如果要先按部门排序,再按工资降序排序:

SELECT first_name, last_name, department, salary
FROM employees
ORDER BY department, salary DESC;

数据检索技巧

使用聚合函数

聚合函数用于对一组值进行计算,并返回单个值。常见的聚合函数有:

  • COUNT():计算行数
  • SUM():计算总和
  • AVG():计算平均值
  • MIN():获取最小值
  • MAX():获取最大值

例如,要计算 employees 表中的员工总数:

SELECT COUNT(*)
FROM employees;

要计算所有员工的总工资:

SELECT SUM(salary)
FROM employees;

计算员工的平均工资:

SELECT AVG(salary)
FROM employees;

获取最低工资和最高工资:

SELECT MIN(salary), MAX(salary)
FROM employees;

分组查询

GROUP BY 子句用于将查询结果按照一个或多个列进行分组。通常与聚合函数一起使用。语法如下:

SELECT column1, aggregate_function(column2)
FROM table_name
GROUP BY column1;

例如,要按部门统计每个部门的员工人数:

SELECT department, COUNT(*)
FROM employees
GROUP BY department;

要按部门计算每个部门员工的平均工资:

SELECT department, AVG(salary)
FROM employees
GROUP BY department;

过滤分组结果

HAVING 子句用于对分组后的结果进行过滤。它与 WHERE 子句类似,但 WHERE 用于过滤行,而 HAVING 用于过滤分组。语法如下:

SELECT column1, aggregate_function(column2)
FROM table_name
GROUP BY column1
HAVING condition;

例如,要获取平均工资大于 8000 的部门及其平均工资:

SELECT department, AVG(salary)
FROM employees
GROUP BY department
HAVING AVG(salary) > 8000;

连接多个表

在实际应用中,数据通常分布在多个相关的表中。通过表连接,可以将多个表中的数据关联起来进行检索。常见的连接类型有:

  • 内连接(INNER JOIN):返回两个表中满足连接条件的所有行。
SELECT column1, column2
FROM table1
INNER JOIN table2 ON table1.common_column = table2.common_column;

例如,假设有 employees 表和 departments 表,employees 表中有 department_id 列,departments 表中有 id 列,要获取员工的名字、姓氏以及所在部门的名称:

SELECT employees.first_name, employees.last_name, departments.department_name
FROM employees
INNER JOIN departments ON employees.department_id = departments.id;
  • 左连接(LEFT JOIN):返回左表(LEFT JOIN 左边的表)中的所有行,以及右表中满足连接条件的行。如果右表中没有匹配的行,则结果集中对应列的值为 NULL
SELECT column1, column2
FROM table1
LEFT JOIN table2 ON table1.common_column = table2.common_column;

例如,要获取所有员工及其所在部门(包括没有分配部门的员工):

SELECT employees.first_name, employees.last_name, departments.department_name
FROM employees
LEFT JOIN departments ON employees.department_id = departments.id;
  • 右连接(RIGHT JOIN):与左连接相反,返回右表中的所有行,以及左表中满足连接条件的行。
SELECT column1, column2
FROM table1
RIGHT JOIN table2 ON table1.common_column = table2.common_column;
  • 全外连接(FULL OUTER JOIN):返回两个表中的所有行。如果某行在另一个表中没有匹配的行,则结果集中对应列的值为 NULL。不过,MySQL 本身不直接支持 FULL OUTER JOIN,可以通过 LEFT JOINRIGHT JOIN 的并集来模拟:
SELECT column1, column2
FROM table1
LEFT JOIN table2 ON table1.common_column = table2.common_column
UNION
SELECT column1, column2
FROM table1
RIGHT JOIN table2 ON table1.common_column = table2.common_column;

子查询

子查询是指在一个 SELECT 语句中嵌套另一个 SELECT 语句。子查询可以用于多种场景,比如作为 WHERE 子句中的条件,或者作为一个临时表。

  • 子查询作为 WHERE 子句的条件:例如,要获取工资高于平均工资的员工:
SELECT first_name, last_name, salary
FROM employees
WHERE salary > (SELECT AVG(salary) FROM employees);

这里,内部的子查询 (SELECT AVG(salary) FROM employees) 先计算出平均工资,然后外部查询根据这个平均工资筛选出工资高于它的员工。

  • 子查询作为临时表:例如,假设有一个 orders 表,记录了订单信息,包括 order_idcustomer_idorder_date 等列,还有一个 order_items 表,记录了每个订单的具体商品信息,包括 order_idproduct_idquantity 等列。要获取每个客户最近的订单及其包含的商品数量,可以这样写:
SELECT sub.customer_id, sub.order_date, sub.product_count
FROM
(
    SELECT o.customer_id, o.order_date, COUNT(oi.product_id) AS product_count,
           ROW_NUMBER() OVER (PARTITION BY o.customer_id ORDER BY o.order_date DESC) AS rn
    FROM orders o
    JOIN order_items oi ON o.order_id = oi.order_id
) sub
WHERE sub.rn = 1;

这里,内部子查询首先使用 ROW_NUMBER() 窗口函数为每个客户的订单按日期降序编号,然后外部查询只选择每个客户编号为 1(即最近的订单)的记录。

使用 LIMITOFFSET

LIMIT 子句用于限制 SELECT 语句返回的行数,OFFSET 用于指定从结果集的哪一行开始返回。语法如下:

SELECT column1, column2
FROM table_name
LIMIT [offset,] row_count;

例如,要获取 employees 表中的前 10 条记录:

SELECT *
FROM employees
LIMIT 10;

要获取从第 11 条记录开始的 10 条记录:

SELECT *
FROM employees
LIMIT 10 OFFSET 10;

这在分页查询中非常有用,比如在 Web 应用中,每次只显示一部分数据。

处理 NULL

在数据库中,NULL 表示一个未知或缺失的值。在 SELECT 语句中,可以使用 IS NULLIS NOT NULL 来处理 NULL 值。例如,要获取 employees 表中没有分配部门的员工(假设 department_id 列在没有部门时为 NULL):

SELECT first_name, last_name
FROM employees
WHERE department_id IS NULL;

要获取有分配部门的员工:

SELECT first_name, last_name
FROM employees
WHERE department_id IS NOT NULL;

使用 CASE 表达式

CASE 表达式允许根据条件在查询结果中返回不同的值。它有两种形式:简单 CASE 表达式和搜索 CASE 表达式。

  • 简单 CASE 表达式
CASE expression
    WHEN value1 THEN result1
    WHEN value2 THEN result2
    ELSE result3
END

例如,根据员工的工资范围给员工评级:

SELECT first_name, last_name, salary,
       CASE 
           WHEN salary < 5000 THEN 'Low'
           WHEN salary >= 5000 AND salary < 8000 THEN 'Medium'
           ELSE 'High'
       END AS salary_rating
FROM employees;
  • 搜索 CASE 表达式
CASE
    WHEN condition1 THEN result1
    WHEN condition2 THEN result2
    ELSE result3
END

例如,根据员工的工作年限给员工奖励:

SELECT first_name, last_name, years_of_service,
       CASE 
           WHEN years_of_service < 5 THEN 'Small bonus'
           WHEN years_of_service >= 5 AND years_of_service < 10 THEN 'Medium bonus'
           ELSE 'Large bonus'
       END AS bonus_type
FROM employees;

处理日期和时间数据

MySQL 提供了丰富的函数来处理日期和时间数据。常见的日期和时间类型有 DATETIMEDATETIMETIMESTAMP

  • 获取当前日期和时间
SELECT CURDATE(); -- 获取当前日期
SELECT CURTIME(); -- 获取当前时间
SELECT NOW(); -- 获取当前日期和时间
  • 日期和时间的计算:例如,要计算员工入职 5 年后的日期(假设 hire_date 是员工入职日期):
SELECT first_name, last_name, hire_date, ADDDATE(hire_date, INTERVAL 5 YEAR) AS five_year_anniversary
FROM employees;
  • 日期和时间的格式化:要将日期格式化为特定的字符串格式,可以使用 DATE_FORMAT() 函数。例如,将员工入职日期格式化为 YYYY - MM - DD 的形式:
SELECT first_name, last_name, DATE_FORMAT(hire_date, '%Y-%m-%d') AS formatted_hire_date
FROM employees;

处理字符串数据

MySQL 也提供了许多字符串处理函数。

  • 字符串连接:使用 CONCAT() 函数将多个字符串连接起来。例如,将员工的名字和姓氏连接成一个完整的姓名:
SELECT CONCAT(first_name,'', last_name) AS full_name
FROM employees;
  • 字符串长度:使用 LENGTH() 函数获取字符串的长度。例如,获取员工名字的长度:
SELECT first_name, LENGTH(first_name) AS name_length
FROM employees;
  • 字符串查找和替换LOCATE() 函数用于查找子字符串在字符串中的位置,REPLACE() 函数用于替换字符串中的子字符串。例如,将员工名字中的 a 替换为 A
SELECT first_name, REPLACE(first_name, 'a', 'A') AS replaced_name
FROM employees;

通过掌握这些 MySQL SELECT 语句的基础和数据检索技巧,可以更加高效地从数据库中获取所需的数据,满足各种业务需求。在实际应用中,需要根据具体的场景和数据特点,灵活运用这些知识来优化查询性能和获取准确的结果。同时,随着数据库规模的扩大,还需要关注查询的效率和资源消耗,合理使用索引等技术来提升整体性能。