SQL进阶必备:从计算字段到多表联结,让查询效率翻倍!

一、创建计算字段:让数据"按需重组"

存储在数据库中的原始数据,往往不符合直接使用的格式(比如分散在多列的信息、需要计算的数值),这时候"计算字段"就能派上用场------它不是表中实际存在的列,而是运行时通过SQL语句动态创建的虚拟列。

1. 核心用法:拼接与算术运算

  • 字段拼接 :用Concat()函数将多列数据合并为一个字段,比如将供应商名称和国家拼接成"名称(国家)"格式:

    sql 复制代码
    SELECT Concat(RTrim(vend_name), '(', RTrim(vend_country), ')') AS vend_title
    FROM vendors;

    其中RTrim()用于去除字段右侧多余空格,AS给计算字段起别名(别名是客户机引用该列的关键)。

  • 算术计算 :直接对数值型字段进行加减乘除运算,比如计算订单中每项物品的总金额(单价×数量):

    sql 复制代码
    SELECT prod_id, quantity, item_price,
    quantity * item_price AS expanded_price
    FROM orderitems WHERE order_num = 20005;

2. 关键技巧:别名的正确使用

别名不仅能简化计算字段的引用,还能解决列名含特殊字符、名称不清晰的问题。命名时建议简洁明了,比如用total_price代替quantity*item_price,让SQL语句更易读。

二、数据处理函数:给数据"做精加工"

函数是SQL处理数据的"工具箱",能快速完成文本格式化、日期计算、数值转换等操作。MySQL支持文本、日期时间、数值三类常用函数,重点掌握这些高频用法:

1. 文本处理函数:搞定字符串格式

  • 大小写转换:Upper()(转大写)、Lower()(转小写)

  • 截取与查找:Left()(取左侧字符)、Locate()(查找子串位置)

  • 去空格:Trim()(去除首尾空格)、RTrim()(去除右侧空格)

  • 语音匹配:Soundex()(按发音匹配字符串,比如匹配"Y.Lee"和"Y.Lie"):

    sql 复制代码
    SELECT cust_name FROM customers
    WHERE Soundex(cust_contact) = Soundex('Y Lie');

2. 日期时间函数:精准处理时间数据

日期是SQL查询中高频过滤条件,核心函数用法如下:

  • 获取当前时间:Now()(日期+时间)、CurDate()(仅日期)

  • 提取日期成分:Year()(年份)、Month()(月份)、Day()(天数)

  • 日期比较:用Date()函数忽略时间部分,只对比日期:

    sql 复制代码
    SELECT cust_id FROM orders
    WHERE Date(order_date) = '2005-09-01';

3. 数值处理函数:简化数学运算

常用函数包括Abs()(绝对值)、Rand()(随机数)、Sum()(求和)等,多用于数值型数据的统计与转换。

三、汇总数据:用聚集函数快速统计

当需要对数据进行统计分析(比如求平均值、计数、找最值)时,不需要逐行检索数据,直接用聚集函数就能快速得到结果。

1. 5个核心聚集函数

函数 功能
AVG() 返回某列平均值(忽略NULL值)
COUNT() 统计行数(COUNT(*)含NULL,COUNT(列名)不含NULL)
MAX() 返回某列最大值
MIN() 返回某列最小值
SUM() 返回某列值之和

2. 实用示例

  • 计算所有产品的平均价格:

    sql 复制代码
    SELECT AVG(prod_price) AS avg_price FROM products;
  • 统计有电子邮件的客户数量:

    sql 复制代码
    SELECT COUNT(cust_email) AS num_cust FROM customers;
  • 合计某订单的总金额:

    sql 复制代码
    SELECT SUM(quantity * item_price) AS total FROM orderitems WHERE order_num = 20005;

四、分组数据:按条件分类统计

汇总函数默认对整个表生效,而GROUP BY子句能将数据按指定列分组,让聚集函数对每个组单独计算,比如"统计每个供应商的产品数量""每个客户的订单数"。

1. 基础用法:GROUP BY + 聚集函数

sql 复制代码
SELECT vend_id, COUNT(*) AS num_prods
FROM products GROUP BY vend_id;

该语句按vend_id分组,统计每个供应商的产品数量。

2. 关键补充:HAVING过滤分组

WHERE用于过滤行,HAVING用于过滤分组(只能跟在GROUP BY后)。比如筛选出产品数量≥2且单价≥10的供应商:

sql 复制代码
SELECT vend_id, COUNT(*) AS num_prods
FROM products WHERE prod_price >= 10
GROUP BY vend_id HAVING COUNT(*) >= 2;

3. 注意事项

  • GROUP BY后列出的列,必须是SELECT中的非聚集列(或表达式);
  • 分组后如需排序,需加ORDER BYGROUP BY不保证分组顺序)。

五、子查询:用"查询嵌套"解决复杂问题

子查询(嵌套查询)是将一个查询结果作为另一个查询的条件或字段,适合解决"多步骤"的数据检索,比如"找出订购了某产品的所有客户"。

1. 核心场景:WHERE子句中的子查询

比如查找订购了产品TNT2的客户名称,需分3步:①找含TNT2的订单号→②找这些订单对应的客户ID→③找客户ID对应的客户信息,用子查询可合并为一条语句:

sql 复制代码
SELECT cust_name FROM customers
WHERE cust_id IN (
  SELECT cust_id FROM orders
  WHERE order_num IN (
    SELECT order_num FROM orderitems WHERE prod_id = 'TNT2'
  )
);

2. 进阶用法:作为计算字段的子查询

比如统计每个客户的订单总数,将子查询作为计算字段:

sql 复制代码
SELECT cust_name,
(SELECT COUNT(*) FROM orders WHERE orders.cust_id = customers.cust_id) AS orders
FROM customers;

这种"相关子查询"会对外部查询的每一行执行一次内部查询,需注意列名的完全限定(比如orders.cust_id),避免歧义。

六、联结表:打破数据孤岛(重点!)

关系数据库中,数据被分散存储在多个表中(比如客户表、订单表、产品表),联结(JOIN)是将这些表按关联关系组合查询的核心技术,也是SQL最强大的功能之一。

1. 先搞懂:为什么需要联结?

比如要查询"客户名称+订单号+订购产品",这些信息分散在customersordersorderitems三个表中,只有通过联结才能一次性检索,避免数据重复存储(比如客户信息不会在每个订单中重复)。

2. 基础联结:内部联结(等值联结)

最常用的联结方式,通过两表中相同的列(比如vendors.vend_idproducts.vend_id)匹配数据:

sql 复制代码
SELECT vend_name, prod_name, prod_price
FROM vendors, products
WHERE vendors.vend_id = products.vend_id;

或用标准SQL的INNER JOIN语法(更清晰,推荐使用):

sql 复制代码
SELECT vend_name, prod_name, prod_price
FROM vendors INNER JOIN products
ON vendors.vend_id = products.vend_id;

3. 关键提醒:避免笛卡儿积

如果联结时忘记写WHEREON条件,MySQL会返回两表的"笛卡儿积"(行数=表1行数×表2行数),导致数据冗余且无意义,一定要注意!

4. 多表联结示例

查询订单20005的客户名称、产品名和数量,需联结3个表:

sql 复制代码
SELECT cust_name, prod_name, quantity
FROM customers, orders, orderitems
WHERE customers.cust_id = orders.cust_id
AND orderitems.order_num = orders.order_num
AND orderitems.order_num = 20005;

总结:SQL进阶的核心逻辑

这6章内容层层递进,从"处理单表数据"(计算字段、函数),到"统计单表数据"(汇总、分组),再到"跨表关联数据"(子查询、联结),本质是逐步提升数据处理的"维度"和"灵活性"。