题解 | #返回顾客名称和相关订单号以及每个订单的总价#

返回顾客名称和相关订单号以及每个订单的总价

http://www.nowcoder.com/practice/4dda66e385c443d8a11570a70807d250

题目分析

初步分析

根据题目要求,我们需要输出:顾客名称、订单号、每个订单的总价(OrderTotal)。根据这个输出,可以初步确定,我们需要三张表的联合查询。

订单总价OrderTotal计算:sum(quantity*item_price)

条件:按顾客名称再按订单号对结果进行升序排序。

题目给出了三个表格,分别为顾客信息表:Customers 、订单信息表:Orders以及商品信息表OrderItems。

进一步分析

我们怎么能让三张表关联起来?

先让两张表之间相互关联。

  1. 先考虑顾客信息表:Customers 、订单信息表:Orders 通过两张表的字段,我们可以通过字段cust_id将两张表关联起来,得到顾客名称

  2. 订单信息表:Orders以及商品信息表OrderItems。 我们可以通过字段order_num关联起来,算出每个订单的总价。

现在,顾客名称有了,每个订单的总价也有了,订单号也能够得到,但是怎么输出呢?

别急,先将上面两步的SQL语句写出来,慢慢分析。

SQL编写分析

SQL1:计算每个订单的总价

因为我们要计算的是每个订单的总价,所以要使用到group by函数对订单进行分组。不然求和的时候,计算的结果是所有的订单总价。

select order_num,sum(quantity*item_price) OrderTotal from OrderItems group by order_num;

我们发现,只要根据上面查询的结果,联合 订单信息表:Orders,我们就能查询每个订单对应的客户编号:cust_id

SQL2:查出每个订单对应的用户id(cust_id)以及订单号

select o.cust_id,t.order_num,t.OrderTotal from Orders o
join 
(select order_num,sum(quantity*item_price) OrderTotal from OrderItems group by order_num) t
on t.order_num=o.order_num;

现在,订单号有了,每个订单的总价也有了,就剩一个顾客的名称。我们可以利用cust_id,将cust_id替换成cust_name,我们的输出就满足题目要求了

SQL3:再来一个连接查询,搞定

select c.cust_name,t.order_num,t.OrderTotal from Orders o
join 
(select order_num,sum(quantity*item_price) OrderTotal from OrderItems group by order_num) t
on t.order_num=o.order_num
join Customers c
on c.cust_id=o.cust_id
order by c.cust_name,t.order_num;

进阶思路

在上面的代码中,我们在连接查询中,增加了一个子查询,从某种程度上说,降低了我们的查询速度。那么,上面的SQL语句有没有办法继续优化呢?答案是肯定的。

认真一想,其实我们的子查询其实是没有必要的。为什么呢?因为这个子查询查出来的字段,我们可以通过在外部再加一个连接查询可以解决。

(select order_num,sum(quantity*item_price) OrderTotal from OrderItems group by order_num) t

在这个子查询中,我们无非就是查出了一个订单编号和每一个订单的总价,并且利用这个子查询中的订单编号作为媒介,与订单信息表Orders 关联了起来。这看起来完全就是多余的。我们完全可以直接利用商品的详细信息表OrderItems订单信息表Orders以及顾客信息表Customers,就能够获取到我们想要的顾客名称以及每个订单的总价。

具体的SQL语句优化后如下:

select c.cust_name,os.order_num,sum(os.quantity*os.item_price) OrderTotal from Orders o
join OrderItems os
on os.order_num=o.order_num
join Customers c
on c.cust_id=o.cust_id
group by c.cust_name,os.order_num
order by c.cust_name,os.order_num;

大家可以思考一下,在优化后的SQL语句中,为什么我们有了两个分组条件?去掉cust_name这个分组条件。结果又会如何?欢迎大家在评论区中探讨。

总结

这个题目主要考察的是多张表的联合查询,中间还穿插着子查询,所以我们自己要分析准确,不然也会被绕晕。做这种题目,主要是一步一步分析,先将简单的SQL语句写出来,再组合成复杂的语句,问题就很容易解决了。

最后,感谢大家阅读我的题解,如果大家有更好的解题思路,希望大家踊跃提出。文中若有什么错误,欢迎大家指正。如果这篇文章对大家有帮助,希望大家帮忙点个赞收藏一下,再次感谢大家。

全部评论
由于默认的 MySQL 配置中 sql_mode 配置了 only_full_group,需要 GROUP BY 中包含所有 在 SELECT 中出现的字段。因此需要在 MySQL 的配置中去掉这个配置。
10 回复 分享
发布于 2022-05-09 13:59
蜗牛有发现题目歧义吗?这题应该是要获得每个顾客的订单总价,因为一个顾客可能有好几个订单,应该是每个顾客相关订单号的总价,而不是每个订单号的总价
9 回复 分享
发布于 2022-05-10 17:50
按照客户编号分组的原因:每个顾客对应着一份订单。我们按照订单分组求总价,自然而然也要按照顾客分组,求出每个订单对应的顾客。
7 回复 分享
发布于 2022-03-09 23:14
我不知道你为什么整这么复杂,突然一看你的解释我都以为是个多么难得题目 select cust_name, b.order_num, sum(quantity*item_price) OrderTotal from Customers a join Orders b on a.cust_id = b.cust_id join OrderItems c on c.order_num =b.order_num group by cust_name,b.order_num order by cust_name,b.order_num 这样不就行了么
4 回复 分享
发布于 2022-08-09 23:22
为什么group by后面必须是c.cust_name,os.order_num呢? 因为:SELECT列表中的列必须是GROUP BY子句中的列或聚合函数,如果group by 后面只有c.cust_name,那么select中就不能有order_num,只能有cust_name【group by后面的列】和OrderTotal【聚合函数】 ,既然select必须有cust_name和order_num,那么group by后面后面就必须也有cust_name和order_num。
4 回复 分享
发布于 2023-08-31 11:24 北京
不需要sum,直接 select c.cust_name,t.order_num,t.OrderTotal from Orders o join (select order_num,quantity*item_price OrderTotal from OrderItems) t on t.order_num=o.order_num join Customers c on c.cust_id=o.cust_id order by c.cust_name,t.order_num; 就好了
3 回复 分享
发布于 2022-03-28 08:26
select cust_name,O.order_num ,quantity*item_price as OrderTotal from Customers C, Orders O, OrderItems OI where C.cust_id=O.cust_id and O.order_num=OI.order_num order by cust_name,order_num
2 回复 分享
发布于 2022-04-14 18:59
您好,我还是没有懂为什么是进行两个分组,能仔细讲解一下吗?
1 回复 分享
发布于 2022-03-11 20:49
输出第二列是订单号,
1 回复 分享
发布于 2023-03-23 14:53 湖北
进阶版的那个使用订单号和客户名来分组的原因: 两个连接把三个表合成一个表之后,会出现一个问题,如果以订单号为依据分组,则最后的select中只能出现订单号和聚合函数,不能出现客户名。因为你不能保证相同订单号的一组中客户名也相同,如果一组里面出现两个客户名,那select显示哪个? 什么?你说一个订单号只属于一位客户?谁说的?创表的sql里连个主键都不写,鬼知道你三个表之间、字段之间有什么关系。你想让MySQL琢磨出题人的意图吗?题目给的不严谨,才导致了这个问题。 另外,哪怕使用了订单号和客户名两个属性来分组,其实也没排除一个订单号对应多个用户的情况,只是让这种情况也可以显示出来了。
1 回复 分享
发布于 2023-07-15 00:47 湖北
select C.cust_name,O.order_num,(select sum(quantity*item_price) from OrderItems where order_num = O.order_num) OrderTotal from Customers C,Orders O where C.cust_id = O.cust_id group by cust_name,order_num order by cust_name,OrderTotal
点赞 回复 分享
发布于 2022-04-04 17:16
不需要sum吧?
点赞 回复 分享
发布于 2022-04-09 13:25

相关推荐

头像
11-09 17:30
门头沟学院 Java
TYUT太摆金星:我也是,好几个华为的社招找我了
点赞 评论 收藏
分享
343 28 评论
分享
牛客网
牛客企业服务