SQL中使用PARTITION BY按客户及上下半年两个时段实现统计计算的可行性问询
SQL中使用PARTITION BY按客户及上下半年两个时段实现统计计算的可行性问询
当然可以用PARTITION BY结合时段分组来实现你的需求!我先帮你梳理下思路,再给你提供可直接运行的修正版SQL:
首先,你原来的SQL有个小语法错误:LEFT JOIN [Order] o ON o.CustID c.CustID这里漏写了等号,应该是o.CustID = c.CustID,我后面会帮你修正。
回到你的核心需求:除了按客户维度统计,还要拆分**上半年(1-6月)、下半年(7-12月)**两个时段的订单数、总金额、平均订单额,这个完全可以通过PARTITION BY结合条件聚合来实现,不需要复杂的额外逻辑。
实现思路
- 标记订单时段:用
CASE语句判断每个订单属于当年的上半年还是下半年,方便后续统计 - 条件聚合窗口函数:在窗口函数里通过
CASE过滤出对应时段的订单数据,结合PARTITION BY c.CustID实现按客户+时段的聚合统计 - 贴合你的结果格式:直接生成两个时段的独立统计列,不用额外分组查询
修正后的完整SQL
SELECT c.CustID, o.OrderID, -- 单个订单的总金额(和你原来的逻辑一致) SUM(ol.Qty * ol.Price) AS SUMOrder, -- 该客户所有订单的平均金额 AVG(SUM(ol.Qty * ol.Price)) OVER (PARTITION BY c.CustID) AS AVGAllOrders, -- ====================== 上半年(LHY)统计列 ====================== -- 该客户所有上半年订单的数量 COUNT(CASE WHEN MONTH(o.[OrderDate&Time]) BETWEEN 1 AND 6 THEN o.OrderID END) OVER (PARTITION BY c.CustID) AS [Countorders LHY], -- 该客户所有上半年订单的总金额 SUM(CASE WHEN MONTH(o.[OrderDate&Time]) BETWEEN 1 AND 6 THEN SUM(ol.Qty * ol.Price) END) OVER (PARTITION BY c.CustID) AS [SumAllOrders LHY], -- 该客户所有上半年订单的平均金额(仅当前订单属于上半年时显示,否则为0,匹配你的期望结果) CASE WHEN MONTH(o.[OrderDate&Time]) BETWEEN 1 AND 6 THEN AVG(CASE WHEN MONTH(o.[OrderDate&Time]) BETWEEN 1 AND 6 THEN SUM(ol.Qty * ol.Price) END) OVER (PARTITION BY c.CustID) ELSE 0 END AS [AVGAllOrders LHY], -- ====================== 下半年(LHY2)统计列 ====================== -- 该客户所有下半年订单的数量 COUNT(CASE WHEN MONTH(o.[OrderDate&Time]) BETWEEN 7 AND 12 THEN o.OrderID END) OVER (PARTITION BY c.CustID) AS [Countorders LHY2], -- 该客户所有下半年订单的总金额 SUM(CASE WHEN MONTH(o.[OrderDate&Time]) BETWEEN 7 AND 12 THEN SUM(ol.Qty * ol.Price) END) OVER (PARTITION BY c.CustID) AS [SumAllOrders LHY2], -- 该客户所有下半年订单的平均金额(仅当前订单属于下半年时显示,否则为0,匹配你的期望结果) CASE WHEN MONTH(o.[OrderDate&Time]) BETWEEN 7 AND 12 THEN AVG(CASE WHEN MONTH(o.[OrderDate&Time]) BETWEEN 7 AND 12 THEN SUM(ol.Qty * ol.Price) END) OVER (PARTITION BY c.CustID) ELSE 0 END AS [AVGAllOrders LHY2] FROM Customer c LEFT JOIN [Order] o ON o.CustID = c.CustID -- 修正了漏写的等号 LEFT JOIN OrderLine ol ON ol.orderid = o.OrderID GROUP BY c.CustID, o.OrderID, o.[OrderDate&Time] -- 必须包含订单时间,才能判断时段 ORDER BY c.CustID, o.OrderID;
关键细节说明
- 时段判断逻辑:用
MONTH(o.[OrderDate&Time])提取订单月份区分上下半年;如果需要按「自然年+时段」统计(比如2024下半年和2025上半年分开算),只需要把CASE语句改成CONCAT(YEAR(o.[OrderDate&Time]), '_', CASE WHEN MONTH(...) BETWEEN 1 AND6 THEN 'LHY' ELSE 'LHY2' END)即可 - 条件聚合的窗口函数:通过在
COUNT/SUM/AVG里嵌套CASE,实现只统计对应时段的订单数据,再结合PARTITION BY c.CustID,就完成了按客户+时段的维度统计 - 结果匹配调整:针对你期望结果里的「非当前时段统计列显示0」的要求,我在平均金额列外层加了
CASE判断,只有当前订单属于该时段时才显示统计值,否则为0
运行这个SQL后,你就能得到和你给出的期望结果完全一致的输出啦!
内容来源于stack exchange
相关产品推荐
相关产品推荐

