在 SQL 查询中,当需要从多个表中获取数据时,“表别名” 和 “联结(JOIN)” 是两个核心且高频的技术点。表别名能简化 SQL 语句,消除列歧义,提升可读性。而各类联结则是实现多表关联查询的基础,直接决定了我们能否高效、准确地获取跨表数据。
本文将围绕表别名、不同类型联结(自联结、自然联结、外部联结等)、带聚集函数的联结及联结条件展开,结合实例详细讲解其用法与应用场景。
表别名是给查询中的表起一个简短的 “昵称”,主要作用是简化 SQL 语句、消除列歧义,尤其在多表查询或表名较长时,能大幅提升编写效率和可读性。
给表起别名的语法非常简单,在表名后直接添加别名,中间可加关键字 AS(也可省略),语法如下:
-- 语法格式 SELECT 列名 FROM 表名 [AS] 别名; -- 多表查询中使用 SELECT 别名1.列名, 别名2.列名 FROM 表名1 [AS] 别名1 JOIN 表名2 [AS] 别名2 ON 联结条件;
示例:现有两张表,product(商品表,含 product_id、name、price、stock、category_id 字段)和 product_category(商品分类表,含 category_id、name),查询商品名称及对应分类名称:
-- 如果使用*通配符,输出所有列,则有字段重复,如 category_id、create_time、update_time 字段重复 > select * from product p join product_category pc on p.category_id=pc.category_id where pc.name='电脑' product_id|name |price |stock|category_id|create_time |update_time |category_id|name|create_time |update_time | ----------+-------------+--------+-----+-----------+-------------------+-------------------+-----------+----+-------------------+-------------------+ 13|联想拯救者Y9000P | 8999.00| 300| 3|2025-01-02 01:49:00|2025-12-31 03:18:08| 3|电脑 |2025-12-31 03:18:08|2025-12-31 03:18:08| 14|苹果MacBook Pro |12999.00| 180| 3|2025-01-11 19:36:00|2025-12-31 03:18:08| 3|电脑 |2025-12-31 03:18:08|2025-12-31 03:18:08| 2 row(s) fetched. -- 不使用表别名(较繁琐) > select product.name as '商品名称', product_category.name as '分类名称' from product join product_category on product.category_id=product_category.category_id where product_category.name='电脑' 商品名称 |分类名称| -----------------+----+ 联想拯救者Y9000P |电脑 | 苹果MacBook Pro |电脑 | 2 row(s) fetched. -- 使用表别名(简洁清晰) > select p.name as '商品名称', pc.name as '分类名称' from product p join product_category pc on p.category_id=pc.category_id where pc.name='电脑' 商品名称 |分类名称| ----------------+----+ 联想拯救者Y9000P |电脑 | 苹果MacBook Pro |电脑 | 2 row(s) fetched.
说明:示例中用 p 作为 product 的别名,pc 作为 product_category 的别名,语句更简洁,且通过别名明确了 category_id 来自哪张表。
联结的本质是通过 “共同字段”(关联键)将多个表的数据组合成一个结果集。根据数据匹配规则的不同,SQL 提供了多种联结类型,核心包括内联结、自联结、自然联结、外部联结等。以下结合实例逐一介绍。
内联结是最常用的联结类型,它只返回两个表中 “关联键匹配成功” 的数据行,不匹配的行将被过滤。
语法如下:
SELECT 列名 FROM 表1 别名1 INNER JOIN 表2 别名2 ON 别名1.关联键 = 别名2.关联键;
示例:查询每个商品的名称和分类名称,只显示有对应分类信息的商品
> select p.name as '商品名称', pc.name as '分类名称' from product p join product_category pc on p.category_id=pc.category_id 商品名称 |分类名称| -------------+----+ 小米14手机 |手机 | 华为Mate60 Pro |手机 | 苹果iPhone 15 |手机 | vivo X100 |手机 | OPPO Find X7 |手机 | 荣耀Magic6 |手机 | 红米K70 |手机 | 一加12 |手机 | 真我GT Neo5 |手机 | 三星S24 Ultra |手机 | 海尔双开门冰箱 |冰箱 | 美的风冷无霜冰箱 |冰箱 | 联想拯救者Y9000P |电脑 | 苹果MacBook Pro|电脑 | 格力落地扇 |风扇 | 美的循环扇 |风扇 | 16 row(s) fetched.
说明:如果商品表中存在 category_id 为 NULL(无分类)的商品,或分类表中无对应 category_id 记录,这些商品将不会出现在结果集中。
自联结并非独立的联结类型,而是一种 “特殊的多表查询” ,将同一张表当作两张不同的表来使用,通过表别名区分,实现同一表内数据的关联查询(如查询员工及其直属经理信息)。
语法核心:必须给同一张表起两个不同的别名,否则无法区分表的两次引用。
SELECT 别名1.列名, 别名2.列名 FROM 表名 别名1 JOIN 表名 别名2 ON 别名1.关联键=别名2.关联键;
实例:使用商品表作为自联结表,别名不同,通过商品 ID 自我联结。
> select p1.name, p2.price from product p1 join product p2 on p1.product_id=p2.product_id where p2.price > 5000 and p1.name like '%苹果%' name |price | -------------+--------+ 苹果iPhone 15 | 7999.00| 苹果MacBook Pro|12999.00| 2 row(s) fetched.
说明:上面的 SQL 语句 JOIN 连接的两张表都是自己,只是别名不同。
自然联结是一种 “简化的内联结”,它会自动查找两张表中 “名称和数据类型都相同的列” 作为关联键,无需手动指定ON子句。
语法如下:
SELECT 列名 FROM 表1 NATURAL JOIN 表2;
实例:使用自然联结查询商品名称、价格、库存以及分类名称
> SELECT p.name, p.price, p.stock, pc.category_name as 'categroy_name' FROM ( select name, price, stock, category_id from product ) p NATURAL JOIN ( select category_id, name as 'category_name' from product_category ) pc where p.price > 5000 name |price |stock|categroy_name| -------------+--------+-----+-------------+ 华为Mate60 Pro | 6999.00| 800|手机 | 苹果iPhone 15 | 7999.00| 1200|手机 | 三星S24 Ultra | 8999.00| 600|手机 | 联想拯救者Y9000P | 8999.00| 300|电脑 | 苹果MacBook Pro|12999.00| 180|电脑 | 5 row(s) fetched.
注意事项:
自然联结的风险:若两张表存在多个同名但无关联意义的列(如都有create_time),会导致错误的关联匹配,因此不建议在复杂表结构中使用。
自然联结默认是内联结,若需保留不匹配的数据,可使用NATURAL LEFT JOIN或NATURAL RIGHT JOIN。
外部联结的核心是 “保留一张表的所有数据行,即使在另一张表中没有匹配的关联键”,未匹配的列将显示为 NULL。根据保留的表不同,分为左外部联结(LEFT OUTER JOIN)、右外部联结(RIGHT OUTER JOIN)和全外部联结(FULL OUTER JOIN),其中 “OUTER” 关键字可省略。
LEFT JOIN(也写作 LEFT OUTER JOIN,OUTER 可省略)的核心作用是保留左表的所有行,即使右表中没有匹配的记录;右表无匹配时,其字段值显示为 NULL。如下图:

语法如下:
SELECT 列名 FROM 左表 别名1 LEFT JOIN 右表 别名2 ON 别名1.关联键=别名2.关联键;
实例:查询所有商品名称和分类名称,如果分类不存在,则商品分类名称返回 NULL。注意,运行下面 SQL 前,先将分类 ID 为 4、5 的分类 ID 修改为 41、51。
> select p.name as '商品名称', p.category_id as '分类ID', pc.name as '分类名称' from product p left join product_category pc on p.category_id=pc.category_id 商品名称 |分类ID|分类名称| -------------+----+----+ 小米14手机 | 1|手机 | 华为Mate60 Pro | 1|手机 | 苹果iPhone 15 | 1|手机 | vivo X100 | 1|手机 | OPPO Find X7 | 1|手机 | 荣耀Magic6 | 1|手机 | 红米K70 | 1|手机 | 一加12 | 1|手机 | 真我GT Neo5 | 1|手机 | 三星S24 Ultra | 1|手机 | 海尔双开门冰箱 | 2|冰箱 | 美的风冷无霜冰箱 | 2|冰箱 | 联想拯救者Y9000P | 3|电脑 | 苹果MacBook Pro| 3|电脑 | 格力落地扇 | 4| | 美的循环扇 | 4| | 16 row(s) fetched.
说明:左表是 product(商品表),因此所有商品都会出现在结果集中,无分类 ID(或者分类 ID 不存在) 的商品其名称为 NULL。
RIGHT JOIN(也写作 RIGHT OUTER JOIN,OUTER 可省略)的核心逻辑与 LEFT JOIN 完全相反:保留右表的所有行,即使左表中没有匹配的记录;左表无匹配时,其字段值显示为 NULL。

注意:上图中,结果表格中 “产品名称”、“分类 ID” 属于商品表,仅仅 “分类名称” 属于分类表。
语法如下:
SELECT 列名 FROM 左表 别名1 RIGHT JOIN 右表 别名2 ON 别名1.关联键 = 别名2.关联键;
实例:查询商品分类下所有的商品,即使分类没有商品也显示出来(为了效果将商品表分类为 4 的改为 41)。
> select p.name as '商品名称', p.category_id as '分类ID', pc.name as '分类名称' from product p right join product_category pc on p.category_id=pc.category_id 商品名称 |分类ID|分类名称| -------------+----+----+ 三星S24 Ultra | 1|手机 | 真我GT Neo5 | 1|手机 | 一加12 | 1|手机 | 红米K70 | 1|手机 | 荣耀Magic6 | 1|手机 | OPPO Find X7 | 1|手机 | vivo X100 | 1|手机 | 苹果iPhone 15 | 1|手机 | 华为Mate60 Pro | 1|手机 | 小米14手机 | 1|手机 | 美的风冷无霜冰箱 | 2|冰箱 | 海尔双开门冰箱 | 2|冰箱 | 苹果MacBook Pro| 3|电脑 | 联想拯救者Y9000P | 3|电脑 | | |风扇 | | |办公桌 | 16 row(s) fetched.
全外部联结会保留左表和右表的所有数据行,两边不匹配的列均显示为NULL。如下图:

注意:MySQL不直接支持FULL JOIN,需用LEFT JOIN + UNION + RIGHT JOIN实现;Oracle、SQL Server 等支持。
语法如下(需要数据库支持):
SELECT 列名 FROM emp e FULL JOIN dept d ON e.dept_id = d.dept_id;
MySQL替代方案:
-- 左联结结果 + 右联结中左表无匹配的结果 > select p.name as '商品名称', p.category_id as '分类ID', pc.name as '分类名称' from product p left join product_category pc on p.category_id=pc.category_id union select p.name as '商品名称', p.category_id as '分类ID', pc.name as '分类名称' from product p right join product_category pc on p.category_id=pc.category_id 商品名称 |分类ID|分类名称| -------------+----+----+ 小米14手机 | 1|手机 | 华为Mate60 Pro | 1|手机 | 苹果iPhone 15 | 1|手机 | vivo X100 | 1|手机 | OPPO Find X7 | 1|手机 | 荣耀Magic6 | 1|手机 | 红米K70 | 1|手机 | 一加12 | 1|手机 | 真我GT Neo5 | 1|手机 | 三星S24 Ultra | 1|手机 | 海尔双开门冰箱 | 2|冰箱 | 美的风冷无霜冰箱 | 2|冰箱 | 联想拯救者Y9000P | 3|电脑 | 苹果MacBook Pro| 3|电脑 | 格力落地扇 | 41| | 美的循环扇 | 41| | | |风扇 | | |办公桌 | 18 row(s) fetched.
上面输出中可以看到商品包含了 NULL 信息,且分类名称也包含 NULL 值。
聚集函数(如COUNT()、SUM()、AVG()等)用于对数据进行统计汇总,结合联结可实现跨表统计(如统计每个商品分类的商品数量、每个商品的订单量等)。
注意:使用聚集函数时,需配合GROUP BY分组,分组字段通常是右表的关联键(如分类 ID)。
实例:统计每个商品分类的商品数量
> select pc.category_id, pc.name, count(p.product_id) as '商品数量' from product_category pc left join product p on pc.category_id=p.category_id group by pc.category_id, pc.name category_id|name|商品数量| -----------+----+----+ 1|手机 | 10| 2|冰箱 | 2| 3|电脑 | 2| 4|风扇 | 0| 5|办公桌 | 0| 5 row(s) fetched.
注意:上面 SQL 使用左联结确保所有商品分类(包括无商品的商品分类)都被统计,无商品的商品分类其商品数量为 0。
联结条件是多表查询的核心,直接决定了数据的匹配规则。错误的联结条件会导致结果集错误(如笛卡尔积、数据缺失等),以下是关于联结条件的核心注意事项:
在外部联结中,ON 子句和 WHERE 子句的作用不同,需严格区分:
ON子句:用于指定 “表之间的关联条件”,在联结时就过滤不匹配的数据,会保留左表(左联结)或右表(右联结)的所有行。
WHERE子句:用于过滤 “联结后的结果集”,会过滤掉所有不满足条件的行,包括左表/右表中本应保留的不匹配行。
实例对比:
-- 左联结,ON 子句过滤商品分类为 “电脑” 的分类(保留所有商品,仅匹配“电脑”的分类) > SELECT p.product_id, p.name, p.price, p.stock, p.category_id, pc.name as 'category_name' FROM product p left join product_category pc on p.category_id=pc.category_id and pc.name='电脑' product_id|name |price |stock|category_id|category_name| ----------+-------------+--------+-----+-----------+-------------+ 1|小米14手机 | 4999.00| 1000| 1| | 2|华为Mate60 Pro | 6999.00| 800| 1| | 3|苹果iPhone 15 | 7999.00| 1200| 1| | 4|vivo X100 | 3999.00| 1500| 1| | 5|OPPO Find X7 | 4499.00| 900| 1| | 6|荣耀Magic6 | 4299.00| 1100| 1| | 7|红米K70 | 2499.00| 2000| 1| | 8|一加12 | 4599.00| 850| 1| | 9|真我GT Neo5 | 2599.00| 1800| 1| | 10|三星S24 Ultra | 8999.00| 600| 1| | 11|海尔双开门冰箱 | 3999.00| 200| 2| | 12|美的风冷无霜冰箱 | 2999.00| 150| 2| | 13|联想拯救者Y9000P | 8999.00| 300| 3|电脑 | 14|苹果MacBook Pro|12999.00| 180| 3|电脑 | 15|格力落地扇 | 199.00| 500| 41| | 16|美的循环扇 | 299.00| 400| 41| | 16 row(s) fetched. -- 左联结,WHERE子句过滤商品分类为“电脑”的商品(先联结再过滤,商品分类不是“电脑”的商品均被排除) > SELECT p.product_id, p.name, p.price, p.stock, p.category_id, pc.name as 'category_name' FROM product p left join product_category pc on p.category_id=pc.category_id where pc.name='电脑' product_id|name |price |stock|category_id|category_name| ----------+-------------+--------+-----+-----------+-------------+ 13|联想拯救者Y9000P | 8999.00| 300| 3|电脑 | 14|苹果MacBook Pro|12999.00| 180| 3|电脑 | 2 row(s) fetched.
若忘记写联结条件,或联结条件无效(如关联键不匹配),会产生 “笛卡尔积” —— 左表的每一行都与右表的每一行匹配,结果集行数 = 左表行数 × 右表行数,通常是错误的。
错误示例(无联结条件):
-- 错误:产生笛卡尔积
> SELECT p.product_id, p.name, p.price, p.stock, p.category_id, pc.name as 'category_name'
FROM product p join product_category pc
where pc.name in ('电脑', '冰箱')
product_id|name |price |stock|category_id|category_name|
----------+-------------+--------+-----+-----------+-------------+
1|小米14手机 | 4999.00| 1000| 1|电脑 |
1|小米14手机 | 4999.00| 1000| 1|冰箱 |
2|华为Mate60 Pro | 6999.00| 800| 1|电脑 |
2|华为Mate60 Pro | 6999.00| 800| 1|冰箱 |
3|苹果iPhone 15 | 7999.00| 1200| 1|电脑 |
3|苹果iPhone 15 | 7999.00| 1200| 1|冰箱 |
...
15|格力落地扇 | 199.00| 500| 41|电脑 |
15|格力落地扇 | 199.00| 500| 41|冰箱 |
16|美的循环扇 | 299.00| 400| 41|电脑 |
16|美的循环扇 | 299.00| 400| 41|冰箱 |
32 row(s) fetched.