SSIS如何解析数据不稳定的列

Dra*_*727 4 sql-server ssis

我有一个关于如何解析列的问题,希望 SSIS/数据库专家可以提供帮助:)

这是问题所在。我在 SQL Server 中有一个以字符串/varchar 格式保存的列,需要从中解析出数据。我有商业智能开发工作室(BIDS)和 SSIS 支持。我熟悉使用该工具使用派生列并像使用 BIDS 那样拆分数据。

问题是数据,这里有一个例子。

Easy to parse with derived columns
24 Year     
2 Month 
3 Month 
2 Month 
8 Year  
7 Year

No clue how to approach to parse
1x Month
3x per Month
1-2 x per month
6 days per month
Run Code Online (Sandbox Code Playgroud)

所以我想要做的是,如果数据是标准的,我想将列分成两列,Number(int) 和 DayType(string),如果它属于第二类(不稳定的数据),把它放在一个第三栏,其他。关于如何解决这个问题的任何建议?

补充说明:我想将非标准数据放入另一个第三列,以便我可以查看数据,并在该特定列上运行命令,以编辑掉一些绒毛,然后使数据在应用程序中可用。

例如,每月 3x,取出“x per”,然后将其解析为 Number 和 Daytype 列。

同样在有 1-2 的情况下,我想取较高的数字,而放弃较低的数字,例如每周 4-6 天,保留 6,去掉“一周”并保留天数

bil*_*nkc 7

对于这样的事情,最佳解决方案当然是控制您的输入。也就是说,现实是您必须解析提供的输入。

对于像您的解析这样复杂的事情,我会跳过Derived Column transformation并直接转到Script transformation. 我选择我的源列,Input并创建三个输出列:数字、垃圾和间隔。number 和 Interval 将保存解析的值,而垃圾只会在脚本无法从输入中产生正面或反面时填充。

我使用了两个成员变量, numbersRegex 和 periodDomain。periodDomain只是一个具有可接受值的列表。对于字符串比较,我强制所有内容都小写并希望使用英语。numbersRegex是一个正则表达式,用于识别字符串中的数字。

对于输入的每一行,脚本将根据空格拆分输入值。对于这些令牌中的每一个,我测试令牌中是否有数字。如果是,我们将调用该GetBiggestNumber方法。否则,我们将调用ValidatePeriodDomain一旦所有标记都被处理,那么确保两个值都已设置是很重要的。

GetBiggestNumber 尝试查看数字的所有分组并找到最大的集合。

ValidatePeriodDomain 尝试将当前值与已知的可接受值列表进行比较。

using System.Text.RegularExpressions;
using System.Collections.Generic;

/// <summary>
/// The amazing script transformation
/// </summary>
[Microsoft.SqlServer.Dts.Pipeline.SSISScriptComponentEntryPointAttribute]
public class ScriptMain : UserComponent
{
    Regex numbersRegex;
    List<string> periodDomain;

    /// <summary>
    /// Initialize member variables
    /// </summary>
    public override void PreExecute()
    {
        base.PreExecute();
        // match consecutive digits
        this.numbersRegex = new Regex(@"\d+", RegexOptions.Compiled );
        this.periodDomain = new List<string>(){ "year", "month" };
    }

    /// <summary>
    /// Parse the incoming data
    /// </summary>
    /// <param name="Row">The row that is currently passing through the component</param>
    public override void Input0_ProcessInputRow(Input0Buffer Row)
    {
        string[] parts = Row.Input.Split();
        string period = string.Empty;
        int? foo = null;

        foreach (string token in parts)
        {
            // try to do something with it
            // If the token has a digit in it, then we'll extract the largest value
            // if no digits, then the first token matching our domain is preserved
            if (this.numbersRegex.IsMatch(token))
            {
                foo = GetBiggestNumber(token);
            }
            else
            {
                if (ValidatePeriodDomain(token))
                {
                    period = token;
                }
            }
        }

        // at this point, we've processed the input data
        // If the local variables are in their initial states, then we didn't find
        // anything of note and need to populate the Row.Junk column
        // Why local variables, because can't read from Row.column
        if (period == string.Empty || (foo == null))
        {
            Row.trash = Row.Input;
        }
                    else
                    {
            Row.number = foo.Value;
            Row.Interval = period;
                    }
    }

    private bool ValidatePeriodDomain(string token)
    {
        return (this.periodDomain.Contains(token.ToLower()));
    }

    private int? GetBiggestNumber(string token)
    {
        int? bigOne = null;
        int? current = null;
        // Get all the groups of numbers and compare them
        foreach (Match item in this.numbersRegex.Matches(token))
        {
            current = int.Parse(item.Value);
            if (!bigOne.HasValue)
            {
                bigOne = current;
            }

            if (current.Value > bigOne.Value)
            {
                bigOne = current;
            }
        }

        return bigOne;
    }
}
Run Code Online (Sandbox Code Playgroud)

使用上面的脚本,您可以看到它如何对输入数据进行切片和切块。我在生成以下屏幕截图的代码和发布的内容之间做了一个小改动。我观察到输入值 9000 被分配给 Row.number 但由于该行从未分配过间隔,我将实际的行填充推迟到脚本的末尾(它在

数据流