在SQL Server中如何对SELECT查询内相同值行分组?附现有查询语句
在SQL Server中对SELECT查询的行分组的方法
嘿,要在SQL Server的SELECT语句里对相同值的行分组,核心工具就是GROUP BY子句,另外如果不想合并行但需要分组统计的话,窗口函数OVER(PARTITION BY)也很实用。我结合你的查询语句来给你讲清楚:
一、基础分组:用GROUP BY合并相同值的行
GROUP BY的作用是把指定列值相同的行聚合为一组,通常需要配合聚合函数(比如SUM()、COUNT()、MAX()等)来计算每组的统计结果——毕竟分组后你总得对每组的数据做些汇总操作对吧?
结合你的查询语句调整示例
假设你想按Parcel(也就是pd.trackingno)分组,统计每个包裹的总发送数量、总金额,同时保留该包裹对应的订单、商品标识(这里假设同一包裹的订单/商品信息是一致的,或者你取每组的第一条),可以这样修改你的查询:
SELECT pd.trackingno AS [Parcel], -- 取每组的第一个订单标识,组内值一致时用MAX()/MIN()都可以 MAX(Trim(o.orderno) + '_' + CONVERT(NVARCHAR, pd.groupnum )) AS [Order], MAX(Isnull(vi.[gtin], '''')) AS [Item], MAX(Isnull(i.skuno, '')) AS [Article], MAX(Isnull(ix_clr.skuno, '')) AS [Color], MAX(Isnull(ix_sze.skuno, '')) AS [Size], MAX(Isnull(i.[description], '')) AS [Description], -- 聚合计算该包裹的总金额 SUM(CONVERT(DECIMAL(8, 2), oi.unitprice * oi.quantity)) AS [TotalPrice], -- 聚合计算该包裹的总发送数量 SUM(CONVERT(INT, oi.quantity)) AS [TotalSent] FROM (SELECT orderno, 'S' Type, groupnum FROM shipments WHERE shipbatch BETWEEN ...) pd -- 保留你原查询里的表关联逻辑 JOIN orders o ON pd.orderno = o.orderno JOIN orderitems oi ON o.orderno = oi.orderno JOIN items i ON oi.itemid = i.itemid LEFT JOIN variantinfo vi ON i.variantid = vi.variantid LEFT JOIN itemxref ix_clr ON i.itemid = ix_clr.itemid AND ix_clr.xreftype = 'COLOR' LEFT JOIN itemxref ix_sze ON i.itemid = ix_sze.itemid AND ix_sze.xreftype = 'SIZE' -- 指定分组依据:按包裹号分组 GROUP BY pd.trackingno
注意:SQL Server有严格的语法要求——SELECT里的列要么是GROUP BY子句里的分组列,要么被聚合函数(比如MAX()、SUM())包裹,否则会直接报错哦。
二、不合并行的分组统计:用窗口函数OVER(PARTITION BY)
如果你不想把相同值的行合并,只是想给每行标记分组信息(比如组内序号),或者计算组内的统计值(比如每个包裹的总金额,但保留每一行的商品明细),那用窗口函数会更合适:
比如给同一Parcel的行加上组内序号,同时计算该包裹的总发送数量:
SELECT pd.trackingno AS [Parcel], Trim(o.orderno) + '_' + CONVERT(NVARCHAR, pd.groupnum ) AS [Order], Isnull(vi.[gtin], '''') AS [Item], Isnull(i.skuno, '') AS [Article], Isnull(ix_clr.skuno, '') AS [Color], Isnull(ix_sze.skuno, '') AS [Size], Isnull(i.[description], '') AS [Description], CONVERT(DECIMAL(8, 2), oi.unitprice * oi.quantity) AS [Price], CONVERT(INT, oi.quantity) AS [Sent], -- 组内序号:同一包裹里的行从1开始编号 ROW_NUMBER() OVER(PARTITION BY pd.trackingno ORDER BY oi.quantity) AS [GroupRowNo], -- 组内总发送数量:同一包裹的所有Sent之和,每行都会显示这个汇总值 SUM(CONVERT(INT, oi.quantity)) OVER(PARTITION BY pd.trackingno) AS [TotalGroupSent] FROM (SELECT orderno, 'S' Type, groupnum FROM shipments WHERE shipbatch BETWEEN ...) pd -- 保留原查询的表关联逻辑 JOIN orders o ON pd.orderno = o.orderno JOIN orderitems oi ON o.orderno = oi.orderno JOIN items i ON oi.itemid = i.itemid LEFT JOIN variantinfo vi ON i.variantid = vi.variantid LEFT JOIN itemxref ix_clr ON i.itemid = ix_clr.itemid AND ix_clr.xreftype = 'COLOR' LEFT JOIN itemxref ix_sze ON i.itemid = ix_sze.itemid AND ix_sze.xreftype = 'SIZE'
这种方式下,原来的每行数据都会保留,同时你能得到分组的统计信息,非常适合需要明细+分组汇总的场景。
内容的提问来源于stack exchange,提问作者Aswin Francis




