SQL分组查询问题及店铺区域最佳销售员SQL查询求助
问题1:如何对某列存在重复值、另一列无重复值的查询结果进行分组?
咱们先把问题拆解清楚:你应该是有这么一组数据——某一列(比如「区域」)有重复值,另一列(比如「销售员ID」)是唯一无重复的,想要按重复列分组,同时保留无重复列的对应信息对吧?核心是要明确你分组后想得到什么结果,分两种常见场景来处理:
场景1:按重复列分组,找出每组内的目标记录(比如每组销售额最高的销售员)
这种情况用窗口函数是最灵活的,比如ROW_NUMBER()或者RANK()。举个实际例子,假设你有一张销售表sales(region VARCHAR, salesperson_id INT, total_sales NUMERIC),其中region重复,salesperson_id唯一:
WITH ranked_sales AS ( SELECT region, salesperson_id, total_sales, -- 按区域分组,每组内按销售额倒序排名 ROW_NUMBER() OVER (PARTITION BY region ORDER BY total_sales DESC) AS rn FROM sales ) -- 取每组排名第一的记录 SELECT region, salesperson_id, total_sales FROM ranked_sales WHERE rn = 1;
如果同一区域有多个销售员销售额并列第一,想全部返回的话,把ROW_NUMBER()换成RANK()就行。
场景2:仅对重复列去重,保留每组任意一条无重复列的记录
如果只是想去掉重复列的冗余,保留每组的一条记录,PostgreSQL可以用DISTINCT ON,通用写法还是用窗口函数:
-- PostgreSQL 专属写法,按区域去重,保留每组销售额最高的销售员 SELECT DISTINCT ON (region) region, salesperson_id, total_sales FROM sales ORDER BY region, total_sales DESC; -- 所有SQL都支持的通用写法 WITH region_unique AS ( SELECT region, salesperson_id, total_sales, ROW_NUMBER() OVER (PARTITION BY region ORDER BY salesperson_id) AS rn FROM sales ) SELECT region, salesperson_id, total_sales FROM region_unique WHERE rn = 1;
问题2:查询店铺各区域的最佳销售员
先看你写的SQL,能看出来你已经理清了表之间的关联关系,但有几个小问题:用了隐式连接(逗号分隔表)容易出错,而且缺少分组和筛选最佳销售员的逻辑。我帮你修正并补全,用窗口函数来实现,逻辑更清晰:
首先先明确表的关联关系(根据你的SQL推导):
persona:存销售员的姓名信息,idpersona是主键factura:发票表,idvendedor关联销售员ID,numfactura是发票号detalle:发票明细,关联发票号和商品编号precio:商品价格表,关联商品编号和单价personarama:销售员和区域的关联表,idrama是区域ID
修正后的完整SQL(用CTE,可读性更高)
WITH sales_summary AS ( -- 先计算每个销售员在对应区域的总销售额 SELECT pr.idrama, p.nombre, p.apellido, SUM(d.cantidad * prc.valor) AS valortotal FROM persona p -- 用显式JOIN代替逗号,关联关系更清晰 JOIN factura f ON p.idpersona = f.idvendedor JOIN detalle d ON f.numfactura = d.numfactura JOIN precio prc ON d.referencia = prc.referencia JOIN personarama pr ON p.idpersona = pr.idpersona -- 按区域+销售员分组,计算每个销售员的总销售额 GROUP BY pr.idrama, p.idpersona, p.nombre, p.apellido ), ranked_sales AS ( -- 给每个区域内的销售员按销售额排名 SELECT idrama, nombre, apellido, valortotal, ROW_NUMBER() OVER (PARTITION BY idrama ORDER BY valortotal DESC) AS rn FROM sales_summary ) -- 筛选每个区域排名第一的销售员 SELECT idrama, nombre, apellido, valortotal FROM ranked_sales WHERE rn = 1;
几个关键说明:
- 用显式JOIN代替隐式连接,避免因连接条件写漏导致的笛卡尔积错误;
- 如果你的SQL版本不支持CTE(比如老版本MySQL),可以把CTE改成子查询嵌套;
- 要是同一区域有多个销售员销售额并列第一,想全部返回的话,把
ROW_NUMBER()换成RANK()或者DENSE_RANK(); - 分组时必须包含所有非聚合列(
idrama、nombre、apellido、idpersona),符合SQL的分组规则。
内容的提问来源于stack exchange,提问作者Daniel Esteban Ladino Torres
相关产品推荐
相关产品推荐

