为什么SSIS令牌函数无法计数相邻的列分隔符?
在名为TOKEN()的表达式编辑器中,SQL Server Integration Services 2012的新字符串函数遇到问题 这有助于解析分隔记录。如果记录来自平面文件,则可以使用平面文件源执行此操作。在本例中,我处理的是作为字符串存储在数据库VARCHAR字段中的旧分隔导入记录。现在,它们需要被提取、处理,并作为分隔字符串重新导出。例如: 1^苹果^0001^01/01/2010^食蚁兽^A1为什么SSIS令牌函数无法计数相邻的列分隔符?,ssis,tokenize,sql-server-2012,Ssis,Tokenize,Sql Server 2012,在名为TOKEN()的表达式编辑器中,SQL Server Integration Services 2012的新字符串函数遇到问题 这有助于解析分隔记录。如果记录来自平面文件,则可以使用平面文件源执行此操作。在本例中,我处理的是作为字符串存储在数据库VARCHAR字段中的旧分隔导入记录。现在,它们需要被提取、处理,并作为分隔字符串重新导出。例如: 1^苹果^0001^01/01/2010^食蚁兽^A1 2^香蕉^0002^03/15/2010^熊^B2 3^蔓越莓^0003^4/15/2010
2^香蕉^0002^03/15/2010^熊^B2
3^蔓越莓^0003^4/15/2010^乌鸦^C3 如果这些字符串位于名为OldImportRecord的列中,则分隔符是插入符号(如图所示),我们希望将第五个字段放入派生列中,我们将使用如下表达式:
TOKEN(OldImportRecord,"^",5)
这将返回Anteater、Bear、Crow等。事实上,我们可以为此记录中的每个字段创建派生列(请注意,索引是基于一个字段的),根据需要更改它们,然后构建另一个分隔的记录以供导出
问题出在这里。如果我们的某些数据包含一些空字符串(或呈现为空字符串的null),该怎么办
4^^0004^6/15/2010^鸭子^D4
TOKEN()无法计数相邻的列分隔符,这会导致列计数失败。现在它只看到五列而不是六列。我们的令牌(OldImportRecord,“^”,5)返回“D4”,而不是预期的“Duck”。当我们提取第四列时,我们试图将“Duck”放在日期列中,各种各样的乐趣随之而来
这里有一个局部解决方法:
TOKEN(REPLACE(OldImportRecord,"^^","^ ^"),"^",5)
请注意,这会丢失每秒一次的分隔符对,因此对于类似“5^^^^^ Emu^E5”的字符串,它将失败,该字符串在REPLACE()之后看起来像“5^^^^ Emu^E5”。列计数仍然错误
这是我的全部解决方法。这包括两个嵌套的REPLACE语句()、一个用于删除多余空格的RTRIM()和一个DT_STR cast,因为我希望将结果保留在VARCHAR中:
(DT_STR,255,1252)RTRIM(TOKEN(REPLACE(REPLACE(OldImportRecord,"^^","^ ^"),"^^","^ ^"),"^",5))
我发布这篇文章是为了提供信息,因为其他人可能也会遇到这个问题
是否有人有更好的解决方法,甚至是真正的解决方案?问题原因:
SSIS中的TOKEN
方法使用C++中的strtok
函数实现。我在读这本书的时候收集了这些信息。这是在第113页的注释中提到的(我喜欢这本书!有很多很好的信息。)
我搜索了strtok
函数的实现,找到了以下链接
-此链接中的代码示例显示函数忽略连续分隔符字符
以下SO问题的答案指出,strtok
函数被设计为忽略连续分隔符
我认为,TOKEN
和TOKENCOUNT
函数按照设计工作,但这是否是SSIS的行为方式可能是Microsoft SSIS团队的一个问题
以上部分的原始帖子是一个更新:
我在SSIS 2012中根据您的数据输入创建了一个简单的包。正如您在问题中所述,令牌
函数的行为不符合预期。我同意你的观点,这个功能似乎不起作用。这篇文章不是对你原来问题的回答
下面是另一种以相对简单的方式编写表达式的方法。只有当输入记录中的最后一段始终有一个值(比如A1、B2、C3等)时,这才有效
表达式可以重写为:
此语句将输入记录作为参数,分隔符插入符号(^)作为第二个参数。第三个参数计算按分隔符拆分时记录中的段总数。如果在最后一段中有数据,则保证有两段。然后可以减去1以获取倒数第二个段
(DT_STR,50,1252)TOKEN(OldImportRecord,"^",TOKENCOUNT(OldImportRecord,"^") - 1)
我用数据流任务创建了一个简单的包。OLE DB source检索数据,派生转换根据下面的屏幕截图解析和拆分数据。然后将输出插入到目标表中。您可以在最后一个屏幕截图中看到源表和目标表。目标表有两列。第一列存储倒数第二个段数据和基于分隔符的段计数(这也是不正确的)。您可以注意到最后一条记录没有获取正确的结果。如果最后一条记录没有值8
,则上述表达式将失败,因为表达式的计算结果将为零索引
希望这有助于简化您的表达
如果没有其他人的消息,我建议您登录此问题
创建表格并填充脚本:
数据流任务内部的派生列转换:
源表和目标表中的数据:
令牌不仅跳过相邻的分隔符,还跳过前导和尾随分隔符。因此,使用您的示例,如果您有一个字段“good”字段,如下所示:
^^^0004^6/15/2010^Duck^
1^苹果^0001^01/01/2010^食蚁兽^A1
后跟一个相邻分隔符和前导分隔符,如下所示:
^^^0004^6/15/2010^Duck^
TOKENCOUNT只会找到两个分隔符,最终将0004分配给Token1,6/15/2010分配给Token2,Duck分配给Token3
我用了一种不同的替代品。我没有在相邻的分隔符之间放置空格(这对前导或训练没有帮助),而是使用replace将分隔符用我在文本中绝对找不到的字符包围起来。下面的表达对我很有用。虽然罗嗦,但事实就是这样
(DT_STR,255,1252)REPLACE(TOKEN(REPLACE(OldImportRecord,"^","~^~"),"^",1),"~","")
当然,你会用你想要的任何标记替换数字1,并根据你的需要调整演员阵容。希望有帮助 另一个警告是