SQL技术问询:如何在SQL中查询3张表?以及如何完善销售奖金计算的查询语句
1. 如何在SQL中查询3张表?
查询3张表的核心就是找对表之间的关联字段,用合适的连接方式把它们串起来就行,我给你举几个实用的场景例子:
假设我们有三张关联表:
Salesperson(销售人员表:id,name)Orders(订单表:id,salesperson_id,amount,date)Product(产品表:id,order_id,product_name)
如果只想看有订单记录且对应产品的销售人员,用内连接(INNER JOIN)就够了,这是最常用的场景:
SELECT sp.name, o.amount, p.product_name FROM Salesperson sp INNER JOIN Orders o ON sp.id = o.salesperson_id INNER JOIN Product p ON o.id = p.order_id;
要是你想保留所有销售人员,哪怕他们还没开单,那就换成左连接(LEFT JOIN),没订单的地方可以用COALESCE补个0,看起来更友好:
SELECT sp.name, COALESCE(o.amount, 0) AS total_amount, p.product_name FROM Salesperson sp LEFT JOIN Orders o ON sp.id = o.salesperson_id LEFT JOIN Product p ON o.id = p.order_id;
给你提几个小提醒:
- 给表取短别名(比如
sp、o)能让语句更简洁,还能避免字段名冲突 - 连接条件一定要明确,比如用主键-外键关联,不然会出现笛卡尔积(数据量直接爆炸)
- 根据实际业务选连接类型,别上来就用内连接,不然可能会漏掉你需要的数据
2. 关联Bonus_pay表完成奖金查询语句
先给你修正下现有语句的小问题:FROM前面多了个逗号,WHERE子句也没写完。接下来咱们一步步把Bonus_pay表关联上,满足按年份匹配奖金等级的需求:
首先假设Bonus_pay表的结构是这样的:year(规则生效年份)、min_qualified_amount(当年拿奖金的最低销售额)、bonus_amount(对应奖金金额)。
方法一:直接关联(适合支持JOIN条件用聚合函数的SQL版本)
SELECT sp.name, YEAR(o.date) AS sales_year, SUM(o.amount) AS total_sales, bp.bonus_amount FROM Salesperson sp INNER JOIN Orders o ON sp.id = o.salesperson_id -- 关联奖金表:匹配年份,同时销售额达标 INNER JOIN Bonus_pay bp ON YEAR(o.date) = bp.year AND SUM(o.amount) >= bp.min_qualified_amount -- 必须按销售人员+年份分组,因为奖金是按年评定的 GROUP BY sp.name, YEAR(o.date), bp.bonus_amount;
方法二:子查询先聚合(兼容所有SQL版本)
如果你的SQL版本不允许在JOIN条件里用聚合函数(比如老版MySQL),那就先把每个销售人员每年的销售额算出来,再关联奖金表:
WITH SalesByYear AS ( SELECT sp.id, sp.name, YEAR(o.date) AS sales_year, SUM(o.amount) AS total_sales FROM Salesperson sp INNER JOIN Orders o ON sp.id = o.salesperson_id GROUP BY sp.id, sp.name, YEAR(o.date) ) SELECT s.name, s.sales_year, s.total_sales, bp.bonus_amount FROM SalesByYear s INNER JOIN Bonus_pay bp ON s.sales_year = bp.year AND s.total_sales >= bp.min_qualified_amount;
几个关键细节:
- 用
YEAR(o.date)提取订单年份,和Bonus_pay的year字段匹配,确保用的是当年的奖金规则 - 一定要按销售人员+年份分组,因为奖金是每年评一次的,不能把多年的销售额混在一起算
- 用
INNER JOIN关联奖金表时,自动就筛选出了达标人员,正好符合你要的“显示可获得奖金的人员”需求;如果想显示所有人(包括没达标的),把INNER JOIN换成LEFT JOIN,再加个COALESCE(bp.bonus_amount, 0)就能让没达标的显示0奖金了
内容的提问来源于stack exchange,提问作者julz oh




