我希望我的标题能在一定程度上反映这个问题......
我有表格课程,我每年跟踪学生获得的分数。现在我必须运行一个统计点的查询。但是:任何超过 150 或 150 倍数的行,该学生在那一年都会失去高于 TotaPoints/150 的分数。
这是 SQL 小提琴:http://sqlfiddle.com/#!18/e84bf/10
这是简单的模式,我在这里手动输入 CorrectResult 进行测试:
CREATE TABLE Courses
([Year] int, [Points] int, [CorrectResult] int)
;
INSERT INTO Courses
([Year], [Points], [CorrectResult])
VALUES
(1, 148, 148),
(2, 4, 150),
(3, 149, 299)
;
这是我同时错误的查询:
SELECT
Year,
Points,
CorrectResult,
TotalCredits - LostPointsTally as RelevantPoints
FROM (
SELECT
Year,
Points,
CorrectResult,
TotalCredits,
LAG(LevelGroup, 1, 0) OVER (ORDER BY Year) AS PreviousLevelGroup,
CASE
WHEN LevelGroup > LAG(LevelGroup, 1, 0) OVER (ORDER BY Year) THEN
TotalCredits - (LAG(LevelGroup, 1, 0) OVER (ORDER BY Year) * 150)
ELSE
0
END AS LostPointsTally
FROM (
SELECT
Year,
Points,
CorrectResult,
TotalCredits,
FLOOR(TotalCredits / 150) + 1 AS LevelGroup
FROM (
SELECT
Year,
Points,
CorrectResult,
SUM(CASE
WHEN Points > 150 THEN 150
ELSE Points
END) OVER (ORDER BY Year) AS TotalCredits
FROM Courses
) t
) t1
) t2;
运行此查询,在第 3 行您得到 300,这是错误的。我们需要得到 150+149,即 299。
(我希望我能说清楚,如果没有,我将非常乐意进一步澄清)
请指教
非常感谢
据我了解你的问题,你想要计算一个调整后的运行总计,只要超过 150 的倍数,总计就会被限制在 150 的倍数。后面的行的运行总计从该点开始继续,直到达到下一个 150 倍数。此外,每条记录的分数限制为 150,因此同一年内不可能超过 150 的倍数。
因为每行的计算取决于前一行的重要调整计算,所以我认为这不能使用带有运行总计和 LAG() 函数的简单聚合来完成。这将需要迭代计算,可能使用递归 CTE(公用表表达式)。
以下使用多个 CTE 来构建结果。第一个 CTE 对每年可以贡献的积分进行了限制。第二个 CTE 是递归 CTE,其中以第一年为基础,并递归地包括与前一年结果相结合的后续年份。
我通过计算限制当年运行总和的 LevelUpThreshold
值重新设计了您的
LevelGroup逻辑。然后计算先前调整和+当前调整点并与计算出的
LevelUpThreshold
进行比较以选择新的调整和。 LEAST()
函数对此非常有效。
生成的查询类似于:
WITH CTE_Adjusted_Points AS (
SELECT C.*, LEAST(Points, 150) AS AdjustedPoints
FROM Courses C
),
CTE_Adjusted_Sum AS (
SELECT
P.*,
P.AdjustedPoints AS AdjustedSum
FROM CTE_Adjusted_Points P
WHERE P.Year = 1
UNION ALL
SELECT
P.*,
LEAST(S.AdjustedSum + P.AdjustedPoints, L.LevelUpThreshold) AS AdjustedSum
FROM CTE_Adjusted_Sum S
JOIN CTE_Adjusted_Points P ON P.Year = S.year + 1
CROSS APPLY (
SELECT (S.AdjustedSum / 150 + 1) * 150 AS LevelUpThreshold
) L
)
SELECT S.Year, S.Points, S.AdjustedPoints, S.AdjustedSum, S.CorrectResult
FROM CTE_Adjusted_Sum S
ORDER BY S.Year;
结果(带有一些额外的测试数据):
年份 | 积分 | 调整积分 | 调整后的总和 | 正确结果 |
---|---|---|---|---|
1 | 148 | 148 | 148 | 148 |
2 | 4 | 4 | 150 | 150 |
3 | 149 | 149 | 299 | 299 |
4 | 10 | 10 | 300 | 300 |
5 | 500 | 150 | 450 | 450 |
6 | 70 | 70 | 520 | 520 |
7 | 70 | 70 | 590 | 590 |
8 | 70 | 70 | 600 | 600 |
9 | 70 | 70 | 670 | 670 |
请参阅 this db<>fiddle 以获取工作示例。