我希望编写一个PowerShell脚本,它将遍历SQL脚本文件的内容,查找包含没有WITH语句的TABLE HINTS的行。
示例:
SELECT * FROM dbo.Table (NOLOCK)
SELECT * FROM dbo.Table (INDEX=PK_Table)
SELECT * FROM dbo.Table (NOLOCK,INDEX=PK_Table)
SELECT * FROM dbo.Table (INDEX=PK_Table,NOLOCK)
我想编写一个powershell脚本来查找这些提示并在TABLE HINT之前添加WITH
。
所以他们看起来如下:
SELECT * FROM dbo.Table WITH (NOLOCK)
SELECT * FROM dbo.Table WITH (INDEX=PK_Table)
SELECT * FROM dbo.Table WITH (NOLOCK,INDEX=PK_Table)
SELECT * FROM dbo.Table WITH (INDEX=PK_Table,NOLOCK)
到目前为止,我有以下内容:
foreach ($str in Get-Content "d:\script.sql") {
if ([regex]::IsMatch($str, "\({0,1}NOLOCK\)|\(,NOLOCK\{0,1}\)","IgnoreCase")) {
$strReplace = [regex]::Replace($str, "\({0,1}NOLOCK\)|\(,NOLOCK\{0,1}\)", "WITH $1")
write $strReplace
}
}
但是它不会将WITH
插入到行中并保持匹配和行。
这还需要处理如下脚本:
SELECT Table1.*, Table2.* FROM dbo.Table1 Table1 (NOLOCK)
INNER JOIN dbo.Table2 Table2 (INDEX=PK_Table2, NOLOCK)
ON (Table2.Id = Table1.Id)
以下建议:我使用了以下内容:
$expr = "(?=\([^)]*(?=(NOLOCK|INDEX=|INDEX\())[^)]*\))(?<!WITH\s+)"
if ([regex]::IsMatch($str, "(?=\([^)]*(?=(NOLOCK|INDEX=|INDEX\())[^)]*\))","IgnoreCase")) {
$replaced = $str -replace $expr,"WITH "
答案 0 :(得分:1)
以下尝试将起作用,至少对您的输入样本有效。无法保证
您需要非常仔细地测试所有三种情况。还要考虑边缘情况。
$sample = "
SELECT * FROM dbo.Table (NOLOCK)
SELECT * FROM dbo.Table (INDEX=PK_Table)
SELECT * FROM dbo.Table (NOLOCK,INDEX=PK_Table)
SELECT * FROM dbo.Table (INDEX=PK_Table,NOLOCK)
SELECT * FROM dbo.Table WITH (NOLOCK)
SELECT * FROM dbo.Table WITH (INDEX=PK_Table)
SELECT * FROM dbo.Table WITH (NOLOCK,INDEX=PK_Table)
SELECT * FROM dbo.Table WITH (INDEX=PK_Table,NOLOCK)
"
$expr = "(?=\([^()]*(?=\b(?:NOLOCK|INDEX)\b)[^()]*\))(?<!WITH\s+)"
$sample -replace $expr,"WITH "
结果:
SELECT * FROM dbo.Table WITH (NOLOCK) SELECT * FROM dbo.Table WITH (INDEX=PK_Table) SELECT * FROM dbo.Table WITH (NOLOCK,INDEX=PK_Table) SELECT * FROM dbo.Table WITH (INDEX=PK_Table,NOLOCK) SELECT * FROM dbo.Table WITH (NOLOCK) SELECT * FROM dbo.Table WITH (INDEX=PK_Table) SELECT * FROM dbo.Table WITH (NOLOCK,INDEX=PK_Table) SELECT * FROM dbo.Table WITH (INDEX=PK_Table,NOLOCK)
正则表达式高级别细分:
(?=\([^()]*(?=\b(?:NOLOCK|INDEX)\b)[^()]*\)) # a position followed by the words "INDEX" or
# "NOLOCK" somewhere in parentheses
# (add more keywords if you want)
(?<!WITH\s+) # the same position must not be preceded by "WITH"
这两个环视条件确定了缺少WITH关键字的位置。之后使用-replace
运算符插入它很简单。
详细分解:
(?= # start zero-width look-ahead
\( # "("
[^()]* # any character except "(" and ")", repeat
\b # a word boundary
(?= # start non-matching group
(?:NOLOCK|INDEX) # "NOLOCK" or "INDEX"
) # end group
\b # a word boundary
[^()]* # any character except "(" and ")", repeat
\) # ")"
) # end look-ahead
(?<! # start zero-width negative look-behind
WITH # "WITH"
\s+ # any number of whitespace
) # end look-begind
话虽如此,您的脚本可以更优雅地编写为
(Get-Content -Raw D:\script.sql) -replace $expr,"WITH "
您还可以将输出重定向到新文件
(Get-Content -Raw D:\script.sql) -replace $expr,"WITH " > script_processed.sql
-Raw参数将文件读取为一个大字符串,而不是按行。在这种情况下,逐行处理是没有用的。