如何在SQL Server中计算表格内人员体重的百分比增减
解决SQL Server中体重百分比计算异常的问题
别担心,刚重新接触SQL Server进阶内容遇到问题太正常了,我帮你排查一下这个体重变化百分比计算的问题~
问题根源:计算优先级错误
你得到异常结果(比如Resident 1的83.1体重对应-16.90)的核心原因是算术运算优先级搞反了!
在你的CASE表达式里,当前的计算逻辑是:
[Weight] - FIRST_VALUE([Weight]) / FIRST_VALUE([Weight]) * 100.0
因为除法和乘法的优先级高于减法,实际执行顺序是:[Weight] - ( (初始体重 / 初始体重) * 100 ) → 也就是 体重 - 100,这就导致了83.1-100=-16.90这种完全不符合预期的结果。
修正方案
我们需要给体重差值加上括号,确保先计算当前体重和初始体重的差,再除以初始体重乘以100。同时可以优化代码,把初始体重提前在CTE中计算,避免重复调用FIRST_VALUE函数,提升效率。
修正后的完整代码
;WITH cte AS ( SELECT ServiceUserID, ra.PersonID, ServiceUser, cn.DateDone, TRY_CAST( LEFT( SUBSTRING(cn.Fragment, PATINDEX('%[0-9.-]%', cn.Fragment), 8000), PATINDEX('%[^0-9.-]%', SUBSTRING(cn.Fragment, PATINDEX('%[0-9.-]%', cn.Fragment), 8000) + 'X') - 1 ) AS REAL ) AS [Weight], ra.ScoreMeaning FROM [JSONCareNotes-HOME] cn LEFT OUTER JOIN [JSONRAs-HOME] ra ON ra.PersonID = cn.ServiceUserID WHERE cn.SliderData LIKE '%weigh%' AND cn.Fragment NOT LIKE '%weighed%' ), cte_initial_weight AS ( SELECT ServiceUser, DateDone, [Weight], -- 提前计算每个用户的初始体重 FIRST_VALUE([Weight]) OVER (PARTITION BY [ServiceUser] ORDER BY DateDone ASC) AS InitialWeight FROM cte WHERE [Weight] IS NOT NULL -- 修正WHERE条件:REAL类型不能和空字符串比较 ) SELECT ServiceUser, DateDone, [Weight], CASE WHEN InitialWeight = 0 THEN 0.00 -- 避免除以0 ELSE CONVERT(numeric(10, 2), ([Weight] - InitialWeight) / InitialWeight * 100.0) END AS [Percentage] FROM cte_initial_weight ORDER BY ServiceUser, DateDone ASC;
关键修正点说明
- 计算逻辑修正:给
([Weight] - InitialWeight)加上括号,确保先算差值,再做除法和乘法,得到正确的百分比变化值。 - 优化初始体重计算:新增
cte_initial_weight子句,一次性计算每个用户的初始体重,避免重复调用FIRST_VALUE,提升查询效率。 - 修正WHERE条件:原条件
NOT([Weight] IS NULL) OR [Weight] = ' '存在错误,因为[Weight]是REAL类型,无法和字符串' '比较,直接用[Weight] IS NOT NULL过滤空值即可。
验证结果
以Resident 1为例,如果初始体重是83.1:
- 第一次记录的百分比应该是
(83.1-83.1)/83.1*100 = 0.00 - 如果后续某条记录体重是85.0,百分比就是
(85.0-83.1)/83.1*100 ≈ 2.29
这样结果就符合预期了。
内容的提问来源于stack exchange,提问作者Ant




