SQL Server提取LogText末尾最新DemandQty与OnHandQty值的问题
我们使用SQL Server 2022(v16.0.1000.6)和SSMS v20.2,变更记录会追加到日志表的LogText字符串字段中,最新变更位于字符串末尾。需要从以下示例字符串中提取末尾的DemandQty和OnHandQty最新值:
12:01:07 OnHandQty: 10000.00000000 -> 9743.00000000 12:01:07 OnHandQty: 9743.00000000 -> 10000.00000000 15:24:25 DemandQty: 0 -> 257.00000000 15:31:09 OnHandQty: 10000.00000000 -> 9743.00000000 15:31:09 DemandQty: 257.00000000 -> 127.00000000
期望结果:DemandQty = 127,OnHandQty = 9743,但当前尝试的SQL代码返回NULL,需解决两个问题:
- 如何在反转字符串中找到DemandQty或OnHandQty之前的
->的位置? - 如何提取反转字符串中箭头前的整数值?
用户尝试的SQL代码
DECLARE @inputString NVARCHAR(MAX) = '12:01:07 OnHandQty: 10000.00000000 -> 9743.00000000 12:01:07 OnHandQty: 9743.00000000 -> 10000.00000000 15:24:25 DemandQty: 0 -> 257.00000000 15:31:09 OnHandQty: 10000.00000000 -> 9743.00000000 15:31:09 DemandQty: 257.00000000 -> 127.00000000' -- Reverse the input string to find the last occurrence of 'DemandQty' from the end. DECLARE @reversedString NVARCHAR(MAX) = REVERSE(@inputString); -- Find the position of the first 'DemandQty' in the reversed string. DECLARE @demandQtyPos INT = CHARINDEX('ytqdnamed', @reversedString) - 1; -- 'ytqdnamed' is 'DemandQty' reversed. -- Find the position of the '>-' symbol that comes before the first 'DemandQty' in the reversed string. DECLARE @arrowPos INT = CHARINDEX('>-', @reversedString, @demandQtyPos); -- Extract the value after '>-' and the space. DECLARE @result NVARCHAR(50) = CASE WHEN @arrowPos > 0 THEN -- Extract the substring after '>-' (ignoring the space), and reverse it back to get the correct order. REVERSE(SUBSTRING(@reversedString, @arrowPos + 2, CHARINDEX(' ', @reversedString + ' ', @arrowPos + 2) - @arrowPos - 2)) ELSE NULL END; ------Convert the extracted value to an integer. SELECT CAST(@result AS INT) AS ExtractedIntegerValue;
解决方案
问题1:在反转字符串中定位目标字段前的->位置
你的代码错误在于:用CHARINDEX('>-', @reversedString, @demandQtyPos)时,起始位置@demandQtyPos是CHARINDEX('ytqdnamed', @reversedString)-1,导致从DemandQty反转字符串的前方开始查找,而我们需要在反转字符串的开头到ytqdnamed的位置之间找>-(对应原字符串中DemandQty条目里的->)。
正确定位逻辑:
- 找到反转后目标字段(如
ytqdnamed对应DemandQty)的起始位置 - 截取反转字符串从开头到该位置的子串
- 反转这个子串,找到
->的位置,再反向计算出它在原反转字符串中的位置
问题2:提取反转字符串中箭头后的整数值
找到>-的位置后,箭头后方的内容就是原字符串中->后面的最新值(因字符串反转),截取该段内容后反转回原顺序,再处理小数部分得到整数。
完整可运行代码
DECLARE @inputString NVARCHAR(MAX) = '12:01:07 OnHandQty: 10000.00000000 -> 9743.00000000 12:01:07 OnHandQty: 9743.00000000 -> 10000.00000000 15:24:25 DemandQty: 0 -> 257.00000000 15:31:09 OnHandQty: 10000.00000000 -> 9743.00000000 15:31:09 DemandQty: 257.00000000 -> 127.00000000' -- 提取最新DemandQty DECLARE @revDemand NVARCHAR(MAX) = REVERSE(@inputString); DECLARE @demandStart INT = CHARINDEX('ytqdnamed', @revDemand); DECLARE @demandSub NVARCHAR(MAX) = SUBSTRING(@revDemand, 1, @demandStart); DECLARE @demandArrowPos INT = LEN(@demandSub) - CHARINDEX('->', REVERSE(@demandSub)) + 1; DECLARE @demandValue NVARCHAR(50) = REVERSE(SUBSTRING(@revDemand, @demandArrowPos + 2, CHARINDEX(' ', @revDemand + ' ', @demandArrowPos + 2) - @demandArrowPos - 2)); DECLARE @finalDemand INT = CAST(FLOOR(CAST(@demandValue AS FLOAT)) AS INT); -- 提取最新OnHandQty DECLARE @revOnHand NVARCHAR(MAX) = REVERSE(@inputString); DECLARE @onHandStart INT = CHARINDEX('ytQdnaHnO', @revOnHand); -- OnHandQty反转后的字符串 DECLARE @onHandSub NVARCHAR(MAX) = SUBSTRING(@revOnHand, 1, @onHandStart); DECLARE @onHandArrowPos INT = LEN(@onHandSub) - CHARINDEX('->', REVERSE(@onHandSub)) + 1; DECLARE @onHandValue NVARCHAR(50) = REVERSE(SUBSTRING(@revOnHand, @onHandArrowPos + 2, CHARINDEX(' ', @revOnHand + ' ', @onHandArrowPos + 2) - @onHandArrowPos - 2)); DECLARE @finalOnHand INT = CAST(FLOOR(CAST(@onHandValue AS FLOAT)) AS INT); SELECT @finalDemand AS DemandQty, @finalOnHand AS OnHandQty;
代码说明
- 通过反转字符串定位目标字段的最后一次出现位置
- 精准截取目标字段对应的变更条目片段,定位
->的位置 - 提取变更后的数值字符串,反转回原顺序后转换为整数(处理小数部分)
内容的提问来源于stack exchange,提问作者PurpleHaze

