在 SSIS .dtsx 包中查找 table 个名称

Finding table names in SSIS .dtsx packages

我正在尝试扫描 SSIS .dtsx 包中的 table 名称。是的,我知道我应该使用 [xml] 和一个解析 SQL 语言的工具。这在这个时候似乎是不可能的。 PowerShell 可以理解 [xml],但是 SQL 解析器通常要花费 ++,此时使用 ANTLR 比 acceptable 更需要投资。我乐于接受建议,但我不要求推荐工具。

有两 (2) 个问题。

1) `&.;` does not appear to be recognized as separate from the table name capture item
2) TABLE5 does not appear to be found

是的,我也知道不应将模式名称硬编码到源代码中。它使 DBA 能够管理数据库 difficult/impossible。这就是这里的做法。

如何使正则表达式从捕获中省略 &.*; 并识别 dbo.TABLE5

这是我用来扫描 .dtsx 文件的代码。

PS C:\src\sql> Get-Content .\Find-FromJoinSql.ps1
Get-ChildItem -File -Filter '*.dtsx' |
    ForEach-Object {
        $Filename = $_.Name
        Select-String -Pattern '(FROM|JOIN)(\s|&.*;)+(\S+)(\s|&.*;)+' -Path $_ -AllMatches |
        ForEach-Object {
            if ($_.Matches.Groups.captures[3].value -match 'dbo') {
                "$Filename === $($_.Matches.Groups.captures[3].value)"
            }
        }
    }

这是 .dtsx 文件中文本类型的一小部分示例。

PS C:\src\sql> Get-Content .\sls_test.dtsx
USE ADATABASE;
SELECT * FROM dbo.TABLE1 WHERE F1 = 3;
SELECT * FROM dbo.TABLE2 T2
    FULL OUTER JOIN dbo.TABLEJ TJ
        ON T2.KEY = TJ.KEY;
SELECT * FROM dbo.TABLE3 T3
    INNER JOIN ADATABASE2.dbo.TABLEK
TK ON
T3.user_id = TK.user_id

SELECT * FROM dbo.TABLE4 T4 FULL OUTER JOIN dbo.TABLE5 T5
    ON T4.F1 = T5.F1;
EXIT

运行 该数据的脚本生成:

PS C:\src\sql> .\Find-FromJoinSql.ps1
sls_test.dtsx === dbo.TABLE1
sls_test.dtsx === dbo.TABLE2
sls_test.dtsx === dbo.TABLEJ
sls_test.dtsx === dbo.TABLE3
sls_test.dtsx === ADATABASE2.dbo.TABLEK
TK
sls_test.dtsx === dbo.TABLE4

PS C:\src\sql> $PSVersionTable.PSVersion.ToString()
7.1.5

有些实体(
)在那些文件中没有被替换确实很奇怪。

稍微更改正则表达式模式以捕获如下所示的 dbo.table 个名称。

使用获取内容

$regex = [regex] '(?im)(?:FROM|JOIN)(?:\s|&[^;]+;)+([^\s&]+)(?:\s|&[^;]+;)*'
Get-ChildItem -Path D:\Test -File -Filter '*.dtsx' |
    ForEach-Object {
        $match = $regex.Match((Get-Content -Path $_.FullName -Raw))
        while ($match.Success) {
            "$($_.Name) === $($match.Groups[1].Value)"
            $match = $match.NextMatch()
        } 
    }

使用Select-字符串

至于为什么 Select-String -AllMatches 跳过了你的 Table5。
来自 the docs: " 当 Select-String 在一行文本中找到多个匹配项时,它仍然只为该行发出一个 MatchInfo 对象,但是 Matches 属性 的对象包含所有匹配项。"

这意味着您需要另一个循环来从每个 $MatchInfo 对象中获取所有 $Matches,以便将它们包含在您的输出中:

$pattern = '(?:FROM|JOIN)(?:\s|&[^;]+;)+([^\s&]+)(?:\s|&[^;]+;)*'
Get-ChildItem -Path 'D:\Test' -File -Filter '*.dtsx' |
    ForEach-Object {
        $Filename = $_.Name
        Select-String -Pattern $pattern -Path $_.FullName -AllMatches |
        ForEach-Object {
            # loop again, because each $MatchInfo object may contain multiple
            # $Matches objects if more matches were found in the same line
            foreach ($match in $_.Matches) {
                if ($match.Groups[1].value -match 'dbo') {
                    "$Filename === $($match.Groups[1].value)"
                }
            }
        }
    }

输出:

sls_test.dtsx === dbo.TABLE1
sls_test.dtsx === dbo.TABLE2
sls_test.dtsx === dbo.TABLEJ
sls_test.dtsx === dbo.TABLE3
sls_test.dtsx === ADATABASE2.dbo.TABLEK
sls_test.dtsx === dbo.TABLE4
sls_test.dtsx === dbo.TABLE5

正则表达式详细信息:

(?im)              Use case-insensitive matching and have '^' and '$' match at linebreaks
(?:                Match the regular expression below
                   Match either the regular expression below (attempting the next alternative only if this one fails)
      FROM         Match the characters “FROM” literally
   |               Or match regular expression number 2 below (the entire group fails if this one fails to match)
      JOIN         Match the characters “JOIN” literally
)                 
(?:                Match the regular expression below
   |               Match either the regular expression below (attempting the next alternative only if this one fails)
      \s           Match a single character that is a “whitespace character” (spaces, tabs, line breaks, etc.)
   |               Or match regular expression number 2 below (the entire group fails if this one fails to match)
      &            Match the character “&” literally
      [^;]         Match any character that is NOT a “;”
         +         Between one and unlimited times, as many times as possible, giving back as needed (greedy)
      ;            Match the character “;” literally
)+                 Between one and unlimited times, as many times as possible, giving back as needed (greedy)
(                  Match the regular expression below and capture its match into backreference number 1
   [^\s&]          Match a single character NOT present in the list below
                   A whitespace character (spaces, tabs, line breaks, etc.)
                   The character “&”
      +            Between one and unlimited times, as many times as possible, giving back as needed (greedy)
)                 
(?:                Match the regular expression below
   |               Match either the regular expression below (attempting the next alternative only if this one fails)
      \s           Match a single character that is a “whitespace character” (spaces, tabs, line breaks, etc.)
   |               Or match regular expression number 2 below (the entire group fails if this one fails to match)
      &            Match the character “&” literally
      [^;]         Match any character that is NOT a “;”
         +         Between one and unlimited times, as many times as possible, giving back as needed (greedy)
      ;            Match the character “;” literally
)*                 Between zero and unlimited times, as many times as possible, giving back as needed (greedy)