SSIS派生列:从单列提取数值填充至两列的技术问题
解决SSIS中提取Mbc/abc对应纯数值的问题
嘿,我来帮你搞定这个字符串提取的麻烦!你之前的表达式问题出在两个地方:一是固定长度截取会把后面的非数字字符带进来,二是只能提取第一个匹配项,没法收集所有数值,也没处理无匹配的空值场景。下面给你两种靠谱的解决方案,优先推荐脚本组件,因为它能完美应对你的需求:
方案一:用Script Component(C#)—— 最灵活可靠的选择
这个方式能精准提取所有Mbc/abc后面的纯数值,自动拼接成你要的格式,还能处理无匹配时的Null填充,特别适合你数千条记录的场景:
- 在Data Flow里拖一个Script Component,选「Transformation」类型
- 进入组件编辑后,在「Input Columns」里勾选你的
ProductDetails列 - 切换到「Inputs and Outputs」,给Output 0添加两个新列:
MbcValues,数据类型选DT_WSTR(长度设个足够的,比如50)AbcValues,同样选DT_WSTR
- 点击「Edit Script」,把默认代码替换成以下C#代码:
using System; using System.Text.RegularExpressions; using Microsoft.SqlServer.Dts.Pipeline.Wrapper; using Microsoft.SqlServer.Dts.Runtime.Wrapper; [Microsoft.SqlServer.Dts.Pipeline.SSISScriptComponentEntryPointAttribute] public class ScriptMain : UserComponent { // 预编译正则,匹配"Mbc "或"abc "后面的纯数值(支持整数、小数) private readonly Regex _mbcRegex = new Regex(@"Mbc\s+(\d+\.?\d*)", RegexOptions.Compiled); private readonly Regex _abcRegex = new Regex(@"abc\s+(\d+\.?\d*)", RegexOptions.Compiled); public override void Input0_ProcessInputRow(Input0Buffer Row) { // 处理空输入的情况 if (Row.ProductDetails_IsNull || string.IsNullOrWhiteSpace(Row.ProductDetails)) { Row.MbcValues_IsNull = true; Row.AbcValues_IsNull = true; return; } // 提取所有Mbc对应的数值,用空格拼接 var mbcMatches = _mbcRegex.Matches(Row.ProductDetails); if (mbcMatches.Count == 0) { Row.MbcValues_IsNull = true; } else { string mbcResult = string.Join(" ", mbcMatches.Cast<Match>().Select(m => m.Groups[1].Value)); Row.MbcValues = mbcResult; } // 提取所有abc对应的数值,用空格拼接 var abcMatches = _abcRegex.Matches(Row.ProductDetails); if (abcMatches.Count == 0) { Row.AbcValues_IsNull = true; } else { string abcResult = string.Join(" ", abcMatches.Cast<Match>().Select(m => m.Groups[1].Value)); Row.AbcValues = abcResult; } } }
为啥这个方案好用?
- 正则表达式精准定位关键词后的纯数值,不会把后面的字母带进来
- 自动收集所有匹配项,用空格拼成你要的格式(比如
6.5 1 2.5) - 空输入或者无匹配时,自动把输出列设为Null
- 预编译正则,处理数千条记录也不会慢
方案二:纯SSIS表达式(适合不想用脚本的场景)
如果你坚持用表达式,那得结合TOKEN、FINDSTRING这些函数,但要注意这个方式只能处理固定数量的匹配项(比如你预估最多3个Mbc),扩展性差一些。举个提取Mbc列的例子:
-- 先判断有没有Mbc,没有的话返回Null ISNULL(FINDSTRING(ProductDetails, "Mbc", 1)) ? NULL(DT_WSTR,50) : -- 提取第一个Mbc后的数值 SUBSTRING(ProductDetails, FINDSTRING(ProductDetails, "Mbc", 1)+4, FINDSTRING(SUBSTRING(ProductDetails, FINDSTRING(ProductDetails, "Mbc", 1)+4, 100), " ", 1)-1) + -- 有第二个Mbc就追加 (TOKENCOUNT(ProductDetails, "Mbc") >1 ? " " + SUBSTRING(ProductDetails, FINDSTRING(ProductDetails, "Mbc", 2)+4, FINDSTRING(SUBSTRING(ProductDetails, FINDSTRING(ProductDetails, "Mbc", 2)+4, 100), " ", 1)-1) : "") + -- 有第三个Mbc就追加 (TOKENCOUNT(ProductDetails, "Mbc") >2 ? " " + SUBSTRING(ProductDetails, FINDSTRING(ProductDetails, "Mbc", 3)+4, FINDSTRING(SUBSTRING(ProductDetails, FINDSTRING(ProductDetails, "Mbc", 3)+4, 100), " ", 1)-1) : "")
abc列的表达式只要把所有Mbc换成abc就行。但这种方式要提前知道最多有多少个匹配,不然会漏,而且处理复杂字符串容易出问题,所以还是优先用脚本组件。
内容的提问来源于stack exchange,提问作者Brita
相关产品推荐
相关产品推荐

