基于关联表总量按行筛选超额数量的SQL代码优化请求
简化按分组计算超额数量的SQL代码
需求:基于TableB的限额数据,按GroupLetter和ValueDate分组后,计算TableA中每行的超额数量。原代码已实现需求,但结构冗长,以下是简化后的方案。
原实现代码
IF (SELECT OBJECT_ID('tempdb..#TableA')) IS NOT NULL DROP TABLE #TableA GO CREATE TABLE #TableA ( GroupLetter CHAR(2), Quantity INT, ValueDate DATE ) INSERT INTO #TableA VALUES ('A',1,'01-02-2000'),('A',1,'01-02-2000'),('A',1,'01-02-2000'),('A',2,'01-03-2000'),('A',2,'01-03-2000'), ('B',2,'01-04-2002'),('B',2,'01-05-2002'), ('C',1,'01-02-2003'),('C',1,'01-02-2003'),('C',1,'02-02-2003'), ('D',1,'02-02-2004'),('D',1,'02-02-2004'), ('E',30,'01-02-2005'),('E',3,'01-07-2005'),('E',1,'01-02-2005'), ('F',30,'01-06-2006'),('F',15,'01-06-2006'),('F',2,'01-08-2006'), ('G',1,'01-02-2007') ; IF (SELECT OBJECT_ID('tempdb..#TableB')) IS NOT NULL DROP TABLE #TableB GO CREATE TABLE #TableB ( GroupLetter CHAR(2), Limit INT ) INSERT INTO #TableB VALUES ('A',3), ('B',3), ('c',1), ('D',2), ('E',29), ('F',32), ('G',3) ; ------------------------------------------------ WITH Step1 AS ( SELECT a.GroupLetter, a.Quantity, a.ValueDate, SUM(a.Quantity) OVER (PARTITION BY a.GroupLetter, a.ValueDate ORDER BY a.Quantity DESC ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS RunningQty, b.Limit FROM #TableA a JOIN #TableB b ON a.GroupLetter = b.GroupLetter ) ,Step2 AS ( SELECT *, CASE WHEN RunningQty <= Limit THEN Limit ELSE Limit - LAG(RunningQty,1,0) OVER (PARTITION BY GroupLetter, ValueDate ORDER BY Quantity DESC) END AS Qty FROM Step1 ) ,Step3 AS ( SELECT *, CASE WHEN qty <= 0 THEN Quantity WHEN Quantity - qty > 0 THEN Quantity - qty END AS DeniedQty FROM Step2 ) SELECT dg.GroupLetter, dg.DeniedQty, dg.ValueDate FROM Step3 dg WHERE (dg.DeniedQty > 0 AND dg.DeniedQty IS NOT NULL)
原运行结果
| GroupLetter | DeniedQty | ValueDate |
|---|---|---|
| A | 1 | 2000-01-03 |
| C | 1 | 2003-01-02 |
| E | 1 | 2005-01-02 |
| E | 1 | 2005-01-02 |
| F | 13 | 2006-01-06 |
简化后的代码
IF OBJECT_ID('tempdb..#TableA') IS NOT NULL DROP TABLE #TableA CREATE TABLE #TableA (GroupLetter CHAR(2), Quantity INT, ValueDate DATE) INSERT INTO #TableA VALUES ('A',1,'01-02-2000'),('A',1,'01-02-2000'),('A',1,'01-02-2000'),('A',2,'01-03-2000'),('A',2,'01-03-2000'), ('B',2,'01-04-2002'),('B',2,'01-05-2002'), ('C',1,'01-02-2003'),('C',1,'01-02-2003'),('C',1,'02-02-2003'), ('D',1,'02-02-2004'),('D',1,'02-02-2004'), ('E',30,'01-02-2005'),('E',3,'01-07-2005'),('E',1,'01-02-2005'), ('F',30,'01-06-2006'),('F',15,'01-06-2006'),('F',2,'01-08-2006'), ('G',1,'01-02-2007') IF OBJECT_ID('tempdb..#TableB') IS NOT NULL DROP TABLE #TableB CREATE TABLE #TableB (GroupLetter CHAR(2), Limit INT) INSERT INTO #TableB VALUES ('A',3),('B',3),('c',1),('D',2),('E',29),('F',32),('G',3) -- 简化后的核心逻辑 SELECT a.GroupLetter, -- 计算每行的超额数量:取(当前累计量-限额)和(当前数量-剩余限额)的较大值,且不小于0 IIF( SUM(a.Quantity) OVER (PARTITION BY a.GroupLetter, a.ValueDate ORDER BY a.Quantity DESC ROWS UNBOUNDED PRECEDING) <= b.Limit, 0, GREATEST( SUM(a.Quantity) OVER (PARTITION BY a.GroupLetter, a.ValueDate ORDER BY a.Quantity DESC ROWS UNBOUNDED PRECEDING) - b.Limit, a.Quantity - (b.Limit - LAG(SUM(a.Quantity) OVER (PARTITION BY a.GroupLetter, a.ValueDate ORDER BY a.Quantity DESC), 1, 0) OVER (PARTITION BY a.GroupLetter, a.ValueDate ORDER BY a.Quantity DESC)) ) ) AS DeniedQty, a.ValueDate FROM #TableA a JOIN #TableB b ON a.GroupLetter = b.GroupLetter WHERE -- 过滤出有超额的行 SUM(a.Quantity) OVER (PARTITION BY a.GroupLetter, a.ValueDate ORDER BY a.Quantity DESC ROWS UNBOUNDED PRECEDING) > b.Limit AND IIF( SUM(a.Quantity) OVER (PARTITION BY a.GroupLetter, a.ValueDate ORDER BY a.Quantity DESC ROWS UNBOUNDED PRECEDING) <= b.Limit, 0, GREATEST( SUM(a.Quantity) OVER (PARTITION BY a.GroupLetter, a.ValueDate ORDER BY a.Quantity DESC ROWS UNBOUNDED PRECEDING) - b.Limit, a.Quantity - (b.Limit - LAG(SUM(a.Quantity) OVER (PARTITION BY a.GroupLetter, a.ValueDate ORDER BY a.Quantity DESC), 1, 0) OVER (PARTITION BY a.GroupLetter, a.ValueDate ORDER BY a.Quantity DESC)) ) ) > 0
简化说明
- 精简临时表创建:合并
IF EXISTS判断与删除语句,去掉冗余的GO(非必要场景下可省略),压缩表定义与插入语句的排版。 - 合并CTE步骤:将原有的3层CTE合并为单查询,直接在主查询中计算超额数量,减少中间变量的传递。
- 简化逻辑表达式:使用
IIF和GREATEST函数替代多层CASE,让计算逻辑更直观,明确每行超额数量的计算规则。 - 过滤逻辑内联:将原最后一步的过滤条件直接整合到主查询的
WHERE子句中,避免额外的结果集筛选。
简化后的代码与原代码逻辑完全一致,输出结果相同,但结构更紧凑,可读性更强。
内容的提问来源于stack exchange,提问作者Jayzxc
相关产品推荐
相关产品推荐

