SQL Server字符串列解析:拆分正负值与乘数至不同列
解析SQL Server中的表达式字符串,分离正负项及乘数
我明白你现在需要解析SQL Server里这些包含SUM表达式的字符串,把每个项按正负分开,还要提取对应的乘数。之前用CHARINDEX和普通拆分方法没搞定,那我们可以用递归CTE来拆分每个表达式的各个项,再结合字符串函数处理符号、乘数和字段名,下面是具体的可运行解决方案:
完整SQL代码
-- 创建测试临时表(与你的示例一致) CREATE TABLE #temped (originalstring VARCHAR(100)); INSERT INTO #temped SELECT 'SUM([S720]) - SUM([S719]) * 2 + SUM([S719])'; INSERT INTO #temped SELECT 'SUM([R382]) + SUM([R989])'; INSERT INTO #temped SELECT 'SUM([S716]) * .295'; -- 递归CTE拆分每个表达式的独立项 WITH SplitExpressions AS ( -- 初始化:给所有表达式开头统一加+,确保每个项都有明确符号 SELECT originalstring, CAST('+' + originalstring AS VARCHAR(MAX)) AS modifiedstring, 1 AS itemindex FROM #temped UNION ALL -- 递归拆分每个+/-分隔的项 SELECT originalstring, STUFF(modifiedstring, 1, CHARINDEX(CASE WHEN CHARINDEX('+', modifiedstring, 2) > 0 THEN '+' ELSE '-' END, modifiedstring, 2), '') AS modifiedstring, itemindex + 1 AS itemindex FROM SplitExpressions WHERE CHARINDEX('+', modifiedstring, 2) > 0 OR CHARINDEX('-', modifiedstring, 2) > 0 ), -- 提取每个项的符号和核心内容 ExtractedItems AS ( SELECT originalstring, itemindex, SUBSTRING(modifiedstring, 1, 1) AS sign, -- 提取+/-符号 LTRIM(SUBSTRING(modifiedstring, 2, CHARINDEX(CASE WHEN CHARINDEX('+', modifiedstring, 2) > 0 THEN '+' ELSE '-' END, modifiedstring, 2) - 2)) AS itemcontent FROM SplitExpressions WHERE CHARINDEX('+', modifiedstring, 2) > 0 OR CHARINDEX('-', modifiedstring, 2) = 0 UNION ALL -- 处理最后一个没有后续分隔符的项 SELECT originalstring, itemindex, SUBSTRING(modifiedstring, 1, 1) AS sign, LTRIM(SUBSTRING(modifiedstring, 2, LEN(modifiedstring) - 1)) AS itemcontent FROM SplitExpressions WHERE CHARINDEX('+', modifiedstring, 2) = 0 AND CHARINDEX('-', modifiedstring, 2) = 0 ), -- 拆分每个项的SUM表达式和乘数,同时提取字段名 SplitItemParts AS ( SELECT originalstring, itemindex, sign, -- 分离SUM部分 CASE WHEN CHARINDEX('*', itemcontent) > 0 THEN LTRIM(SUBSTRING(itemcontent, 1, CHARINDEX('*', itemcontent) - 1)) ELSE itemcontent END AS sum_expression, -- 分离乘数,无乘数则默认1 CASE WHEN CHARINDEX('*', itemcontent) > 0 THEN LTRIM(SUBSTRING(itemcontent, CHARINDEX('*', itemcontent) + 1, LEN(itemcontent))) ELSE '1' END AS multiplier, -- 从SUM([XXX])中提取字段名XXX SUBSTRING(itemcontent, CHARINDEX('[', itemcontent) + 1, CHARINDEX(']', itemcontent) - CHARINDEX('[', itemcontent) - 1) AS field_name FROM ExtractedItems ) -- 最终输出:按符号分配到正负列,带出乘数和字段名 SELECT originalstring, CASE WHEN sign = '+' THEN sum_expression ELSE NULL END AS Col_positive, CASE WHEN sign = '-' THEN sum_expression ELSE NULL END AS Col_Neg, multiplier AS Multiplier, field_name AS FieldName FROM SplitItemParts ORDER BY originalstring, itemindex; -- 清理临时表 DROP TABLE #temped;
代码说明
- 统一表达式格式:给每个表达式开头添加
+,确保所有项都有明确的正负符号,避免第一个项无符号的处理麻烦。 - 递归拆分项:通过递归CTE把每个长表达式拆分成带符号的独立项,比如把
SUM([S720]) - SUM([S719]) * 2 + SUM([S719])拆分为+SUM([S720])、-SUM([S719]) * 2、+SUM([S719])三个项。 - 拆分SUM与乘数:对每个项检查是否包含
*,分离出SUM表达式和乘数,没有乘数的项默认乘数为1。 - 提取字段名:利用
CHARINDEX定位[和]的位置,提取出中间的字段名称(如S720、R382)。 - 整理输出:根据项的符号,把SUM表达式放到对应的
Col_positive或Col_Neg列,同时展示乘数和字段名。
测试结果示例
以你提供的第一条表达式为例,输出结果如下:
| originalstring | Col_positive | Col_Neg | Multiplier | FieldName |
|---|---|---|---|---|
| SUM([S720]) - SUM([S719]) * 2 + SUM([S719]) | SUM([S720]) | NULL | 1 | S720 |
| SUM([S720]) - SUM([S719]) * 2 + SUM([S719]) | NULL | SUM([S719]) | 2 | S719 |
| SUM([S720]) - SUM([S719]) * 2 + SUM([S719]) | SUM([S719]) | NULL | 1 | S719 |
这个结果完全符合你的需求:正值项放入Col_positive,负值项放入Col_Neg,每个项的乘数对应显示,同时提取出了对应的字段名。
内容的提问来源于stack exchange,提问作者user2772056
相关产品推荐
相关产品推荐

