SQL 指南:以MySQL为例,从基础到高级查询技巧

SQL(Structured Query Language)是用于管理关系型数据库的标准语言。

而MySQL 作为最流行的开源关系型数据库之一,其 SQL 实现遵循标准,但也拥有一些自身的特性和函数。本文将详细讲解 MySQL 中的各种查询方法,助你高效地获取所需数据。

一、 基础查询 (SELECT)

SELECT 语句用于从数据库中选取数据,这是最核心的查询命令。

  1. 查询所有列 (SELECT *)
    使用星号 (*) 可以返回指定表中的所有列。

    -- 假设我们有一张名为 `employees` 的表
    SELECT * FROM employees;
    

    注意:在生产环境中谨慎使用 SELECT *,最好明确指定需要的列,以减少不必要的网络传输和资源消耗。

  2. 查询特定列 (SELECT column)
    你可以明确指定一个或多个列名,用逗号分隔。

    SELECT first_name, last_name, salary FROM employees;
    
  3. 列别名 (AS)
    使用 AS 关键字可以为列指定一个别名,使结果集更易读。AS 可以省略。

    SELECT
      first_name AS '名',
      last_name AS '姓',
      salary * 12 AS '年薪'
    FROM employees;
    
二、 结果排序 (ORDER BY)

ORDER BY 子句用于对结果集进行排序,默认是升序 (ASC),降序使用 DESC

-- 按薪水从高到低排序
SELECT first_name, salary
FROM employees
ORDER BY salary DESC;

-- 按部门升序排,同部门内按薪水降序排
SELECT first_name, department_id, salary
FROM employees
ORDER BY department_id ASC, salary DESC;
三、 条件过滤 (WHERE)

WHERE 子句用于提取满足指定条件的记录。

  1. 基本运算符 (=, <>/!=, >, <, >=, <=)

    SELECT * FROM employees WHERE salary > 10000;
    SELECT * FROM employees WHERE department_id = 10;
    SELECT * FROM employees WHERE first_name != 'John';
    
  2. 逻辑运算符 (AND, OR, NOT)
    用于组合多个条件。

    -- 薪资在 8000 到 12000 之间的员工
    SELECT * FROM employees
    WHERE salary >= 8000 AND salary <= 12000;
    
    -- 部门是10或20的员工
    SELECT * FROM employees
    WHERE department_id = 10 OR department_id = 20;
    
    -- 除了10部门以外的所有员工
    SELECT * FROM employees WHERE NOT department_id = 10;
    -- 等价于
    SELECT * FROM employees WHERE department_id <> 10;
    
  3. 模糊查询 (LIKE)
    % 代表任意字符(包括0个),_ 代表一个任意字符。

    -- 查找名字以 'J' 开头的员工
    SELECT * FROM employees WHERE first_name LIKE 'J%';
    
    -- 查找名字中包含 'an' 的员工
    SELECT * FROM employees WHERE first_name LIKE '%an%';
    
    -- 查找名字第二个字母是 'o' 的员工
    SELECT * FROM employees WHERE first_name LIKE '_o%';
    
  4. 空值判断 (IS NULL / IS NOT NULL)
    判断字段是否为 NULL不能直接用 = NULL

    -- 查询佣金为空的员工
    SELECT * FROM employees WHERE commission_pct IS NULL;
    
    -- 查询佣金不为空的员工
    SELECT * FROM employees WHERE commission_pct IS NOT NULL;
    
四、 去重与截断
  1. 去重 (DISTINCT)
    返回唯一不同的值。

    -- 查看公司里有哪些不同的部门ID
    SELECT DISTINCT department_id FROM employees;
    
    -- 多列组合去重
    SELECT DISTINCT department_id, job_id FROM employees;
    
  2. 截断与分页 (LIMIT , OFFSET)
    MySQL 使用 LIMIT 来限制返回的记录数,常用于分页。OFFSET 指定开始返回记录前的偏移量。

    -- 查看薪水最高的5名员工
    SELECT * FROM employees
    ORDER BY salary DESC
    LIMIT 5;
    
    -- 实现分页(每页10条,查看第3页的数据)
    -- 公式: LIMIT page_size OFFSET (page_number - 1) * page_size
    SELECT * FROM employees
    LIMIT 10 OFFSET 20; -- 跳过前20条,取接下来的10条
    -- MySQL 也支持简写: LIMIT 20, 10
    
五、 分支表达式 (CASE WHEN)

CASE 表达式用于实现条件逻辑,类似于编程语言中的 if-else。

SELECT
  first_name,
  salary,
  CASE
    WHEN salary > 15000 THEN '高薪'
    WHEN salary BETWEEN 8000 AND 15000 THEN '中等'
    ELSE '普通'
  END AS '薪资等级'
FROM employees;
六、 分组聚合 (GROUP BY & HAVING)
  1. 分组 (GROUP BY)
    将相同值的行分组到一起,并与聚合函数(如 SUM, COUNT, AVG)一起使用。

    -- 单级分组:计算每个部门的平均薪资
    SELECT
      department_id,
      AVG(salary) AS avg_salary
    FROM employees
    GROUP BY department_id;
    
    -- 多级分组:计算每个部门内每个职位的员工数量和总薪资
    SELECT
      department_id,
      job_id,
      COUNT(*) AS employee_count,
      SUM(salary) AS total_salary
    FROM employees
    GROUP BY department_id, job_id;
    
  2. 过滤分组 (HAVING)
    WHERE 在分组过滤行,而 HAVING 在分组过滤分组。

    -- 筛选出员工数量超过5人的部门
    SELECT
      department_id,
      COUNT(*) AS emp_count
    FROM employees
    GROUP BY department_id
    HAVING COUNT(*) > 5;
    
    -- 筛选出平均薪资超过10000的部门
    SELECT
      department_id,
      AVG(salary) AS avg_salary
    FROM employees
    GROUP BY department_id
    HAVING AVG(salary) > 10000;
    
七、 常用函数
  1. 时间函数

    -- 获取当前日期和时间
    SELECT NOW();
    
    -- 获取当前日期
    SELECT CURDATE();
    
    -- 日期格式化
    SELECT DATE_FORMAT(NOW(), '%Y-%m-%d %H:%i:%s'); -- 输出: 2023-10-27 15:30:45
    
    -- 日期加减
    SELECT DATE_ADD(NOW(), INTERVAL 1 DAY); -- 加一天
    SELECT DATE_SUB(NOW(), INTERVAL 1 HOUR); -- 减一小时
    
    -- 计算日期差
    SELECT DATEDIFF('2023-12-31', '2023-10-27'); -- 返回相差的天数
    
  2. 字符串函数

    -- 连接字符串
    SELECT CONCAT(first_name, ' ', last_name) AS full_name FROM employees;
    
    -- 转大写/小写
    SELECT UPPER('hello'), LOWER('WORLD');
    
    -- 截取子串
    SELECT SUBSTRING('MySQL', 3, 3); -- 输出: SQL (从第3位开始,截取3位)
    
    -- 长度
    SELECT LENGTH('Hello'); -- 输出: 5
    
  3. 聚合函数
    COUNT(), SUM(), AVG(), MAX(), MIN()

    SELECT
      COUNT(*) AS total_employees, -- 总行数
      SUM(salary) AS total_salary_payout, -- 总和
      AVG(salary) AS average_salary, -- 平均值
      MAX(salary) AS highest_salary, -- 最大值
      MIN(salary) AS lowest_salary -- 最小值
    FROM employees;
    
八、 高级查询:开窗函数 (Window Functions)

开窗函数对一组行进行计算,但不像 GROUP BY,每个行仍然单独返回。MySQL 8.0+ 开始支持。

  1. SUM OVER():计算分区内的总和

    -- 计算每个员工及其所在部门的总薪资
    SELECT
      first_name,
      department_id,
      salary,
      SUM(salary) OVER(PARTITION BY department_id) AS dept_total_salary
    FROM employees;
    
  2. SUM OVER(ORDER BY):计算累计和

    -- 按薪水排序,计算累计薪水
    SELECT
      first_name,
      salary,
      SUM(salary) OVER(ORDER BY salary) AS running_total
    FROM employees;
    
  3. ROW_NUMBER(), RANK(), DENSE_RANK():排名

    -- 为每个部门内的员工按薪水排名
    SELECT
      first_name,
      department_id,
      salary,
      ROW_NUMBER() OVER(PARTITION BY department_id ORDER BY salary DESC) AS 'row_number_rank',
      RANK() OVER(PARTITION BY department_id ORDER BY salary DESC) AS 'rank',
      DENSE_RANK() OVER(PARTITION BY department_id ORDER BY salary DESC) AS 'dense_rank'
    FROM employees;
    
  4. LAG() / LEAD():访问前面/后面行的数据

    -- 查看当前行和前一个员工的薪水差值
    SELECT
      first_name,
      salary,
      LAG(salary) OVER(ORDER BY salary) AS prev_salary,
      salary - LAG(salary) OVER(ORDER BY salary) AS diff_from_prev
    FROM employees;
    
九、 关联查询 (JOIN)

用于从多个表中查询相关数据。

  1. 内连接 (INNER JOINJOIN)
    返回两个表中连接字段相匹配的行。

    -- 假设还有一张 `departments` 表,有 department_id 和 department_name 字段
    SELECT
      e.first_name,
      e.last_name,
      d.department_name
    FROM employees e -- 使用别名简化
    INNER JOIN departments d ON e.department_id = d.department_id;
    
  2. 左连接 (LEFT JOIN)
    返回左表 (employees) 的所有行,即使右表没有匹配的行。右表无匹配则为 NULL

    -- 查询所有员工及其部门信息(包括没有部门的员工)
    SELECT
      e.first_name,
      d.department_name
    FROM employees e
    LEFT JOIN departments d ON e.department_id = d.department_id;
    
  3. 右连接 (RIGHT JOIN)
    与左连接相反,返回右表的所有行,即使左表没有匹配的行。

  4. 全外连接 (FULL OUTER JOIN)
    返回左右表中所有的行。MySQL 不直接支持 FULL OUTER JOIN,通常用 LEFT JOINRIGHT JOINUNION 来模拟。

十、 子查询 (Subqueries)

一个查询嵌套在另一个查询中。

-- 1. 在 WHERE 中作为条件:查询薪水高于平均薪水的员工
SELECT * FROM employees
WHERE salary > (SELECT AVG(salary) FROM employees);

-- 2. 在 FROM 中作为派生表:查询每个部门的平均薪水,并筛选出高于公司平均薪水的部门
SELECT dept_avg.*
FROM (
  SELECT department_id, AVG(salary) AS avg_sal
  FROM employees
  GROUP BY department_id
) AS dept_avg
WHERE dept_avg.avg_sal > (SELECT AVG(salary) FROM employees);
十一、 组合查询 (UNION & UNION ALL)

用于合并两个或多个 SELECT 语句的结果集。

  • UNION:删除重复的记录。
  • UNION ALL:保留所有记录,包括重复的。性能更好,因为不需要去重。
-- 假设有两张表:current_employees 和 former_employees,结构相同
-- 获取所有当前和过往员工的唯一姓名列表
SELECT first_name FROM current_employees
UNION
SELECT first_name FROM former_employees;

-- 获取所有姓名列表(包括重复的)
SELECT first_name FROM current_employees
UNION ALL
SELECT first_name FROM former_employees;

希望这篇详细的 MySQL 查询方法汇总能成为你学习和工作中的有力参考。实践是掌握 SQL 的最佳途径,打开你的 MySQL 客户端,尝试运行这些示例并修改它们来适应你的数据吧!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

秋名RG

请我喝杯咖啡,让我更有动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值