【问题标题】:How do I write an SSIS Expression to extract one folder name from a fully qualified file name如何编写 SSIS 表达式以从完全限定的文件名中提取一个文件夹名称
【发布时间】:2019-11-26 19:07:44
【问题描述】:

我有一个带有 ForEach 文件枚举循环(完全限定名称)的 SSIS 包,其中包含一个 FTP 任务。

包执行时会遍历以下目录下子文件夹中的文件

C:\Test\Test2\ABC\

*.txt

它会将文件发布到 FTP 站点。

我在 foreach 循环中定义了一个名为 @[User::Filename] 的变量。

但是 FTP 中有文件夹,我希望文件根据从 C 驱动器上获取的文件夹转到。

C:\Test\Test2\ABC\A\1.txt

C:\Test\Test2\ABC\B\2.txt

C:\Test\Test2\ABC\C\3.txt

文件 1.txt 应该转到名为 \FTP\A 的 FTP 文件夹

文件 2.txt 应该转到名为 \FTP\B 的 FTP 文件夹

文件 3.txt 应该转到名为 \FTP\C 的 FTP 文件夹

我最初的想法是使远程路径成为一个变量,并从 foreach 循环变量中提取完全限定名称。

为此,我创建了一个名为 @[User::FilenameFTP] 的变量并将以下内容输入到表达式中

"//FTP//" + 

 RIGHT(
       (LEFT(@[User::Filename], ABS((FINDSTRING(@[User::Filename], "//", 5)))), 

       ABS((FINDSTRING(@[User::Filename], "//", 5)-1)) - ABS((FINDSTRING(@[User::Filename], "//",4)+1))
      )

我认为这个公式会给我文件来自的 C 驱动器中的文件名,我将其用作 FTP 任务中的远程路径变量。但是当我运行它时,文件仍然进入 \FTP\ 而不是进入子文件夹。

我对此运行了一个脚本任务,但输出也没有显示我想要的。我究竟做错了什么?不能以这种方式在 foreach 循环中编辑变量吗?

【问题讨论】:

    标签: sql visual-studio ssis sql-server-data-tools


    【解决方案1】:

    如果您的驱动器名称(或多或少)如您所显示的那样出现,那么这些应该是反斜杠 ("\\"),而不是表达式中的正斜杠。可能不是问题,但我改变了它们来解决这个问题。

    使用 C 文件夹字符串,在所写的表达式中,ABS((FINDSTRING(@[User::Filename], "\\", 5)-1))ABS((FINDSTRING(@[User::Filename], "\\",4)+1)) 都计算为 19,因此表达式归结为 RIGHT(<<String>>,0),并且根据文档,If integer_expression is zero, the function returns a zero-length string.。因此,您不会在 FTP 基本文件夹名称的末尾附加任何内容。

    问题修复

    我们可能会搞砸所有 LEFTRIGHTFINDSTRING,但如果您知道您所追求的文件夹名称将始终是您完全限定名称中的第五个元素(您的表达式已经依赖)你可以更快地到达那里,只需使用TOKEN,并指定斜杠分隔字符串的第五个元素:

    "//FTP//" + TOKEN( @[User::Filename],"\\",5) +"//"
    

    计算结果为//FTP//C//

    更可持续的修复

    另一方面,如果您想对您的代码进行一点面向未来的验证,预计有一天您会添加或删除文件夹层次结构,我建议您提取最后一个文件夹名称,而不管有多少文件夹的级别排在第一位。

    我们可以使用SUBSTRING 和一些聪明的REVERSE 工作来做到这一点,并应归功于KeithLthis answer,这让我滚动。

    SUBSTRING 接受三个参数。我们有我们的字符串@[User::Filename],这就是一个。第二个是从字符串左端开始的位置,第三个是要提取的字符数。

    要获得起始位置,我们将使用REVERSE 从字符串的右侧开始计数字符,从而找到倒数第二个斜杠的位置:

    FINDSTRING(REVERSE( @[User::Filename]),"\\",2) (evaluates to 8 here)
    

    所以我们的起始位置是字符串的总长度,减去倒数第二个斜杠的字符数。

    LEN( @[User::Filename]) - FINDSTRING(REVERSE( @[User::Filename]),"\\",2) (=17)
    

    我们可以通过从倒数第二个斜杠的反转位置减去最后一个斜杠的反转位置,然后再减去一个来获得要提取的字符数,因为我们不希望字符串中出现尾随斜杠.

    FINDSTRING(REVERSE( @[User::Filename]),"\\",2) 
    - FINDSTRING(REVERSE( @[User::Filename]),"\\",1) - 1 (= 1 in our example)
    

    还有我们的三个论点。将这些与您的基本文件夹名称放在一起(我添加了一个斜杠。如果这对您不起作用,请将其从那里取出!):

    "//FTP//" 
    + SUBSTRING( 
          @[User::Filename] ,
          LEN( @[User::Filename]) - FINDSTRING(REVERSE( @[User::Filename]),"\\",2),
          FINDSTRING(REVERSE( @[User::Filename]),"\\",2)
            -FINDSTRING(REVERSE( @[User::Filename]),"\\",1)-1 )
    + "//"
    

    评估为//FTP//C//

    现在,当决定“清理”源服务器的权力,并且Test2 层突然消失,或者事情变得疯狂,并且你将这一切埋得更深一层时,你的代码仍然会工作。

    旁注

    如果您确实在文件路径名中使用了驱动器号,例如C:\,请注意,当您在本地运行包时,这是包正在使用的 C:\ 驱动器,但是当您部署它时,它会在服务器的 C:\ 驱动器上四处寻找,它可能不喜欢它找到的东西,或者更可能的是,在那里找不到。

    【讨论】:

    • 埃里克非常感谢你!我使用了您提到的 Token 命令,它完全按照我的预期工作。我将审查您的长期解决方案,并提到在部署到生产环境时可能值得。再次感谢您,我正在为此苦苦挣扎。
    • @JustinStaugaitis,SSIS 表达几乎总是一场斗争!与标准 SQL 的不同之处足以让您发疯。很高兴它有帮助!
    猜你喜欢
    • 2017-02-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-04-21
    • 1970-01-01
    • 1970-01-01
    • 2011-04-13
    • 1970-01-01
    相关资源
    最近更新 更多