格式化 TSQL 字符串以使用 ASP.NET 模仿 SQL 管理器的最佳方法是什么?

What is the best way to format a TSQL string to mimic SQL Manager using ASP.NET?

使用 SMO 和 ASP.NET,我正在尝试将突出显示和行格式添加到 SMO 对象(table、视图等)的脚本方法中。目前我正在使用 String.Replace 方法来匹配关键字,但这似乎并没有捕获所有的关键字。我有一个数组中的关键字,然后循环匹配 TSQL 脚本。我不确定我需要匹配哪些字符才能获取所有关键字并获取类似于 SQL Manager.

的行格式
    Dim searchArr As Array = {"ADD", "EXTERNAL", "PROCEDURE", "ALL", "FETCH", "PUBLIC", "ALTER", "FILE", "RAISERROR", "AND", "FILLFACTOR", "READ", "ANY", "FOR", "READTEXT", "AS", "FOREIGN", "RECONFIGURE",
                "ASC", "FREETEXT", "REFERENCES", "AUTHORIZATION", "FREETEXTTABLE", "REPLICATION", "BACKUP", "FROM", "RESTORE", "BEGIN", "FULL", "RESTRICT", "BETWEEN", "FUNCTION", "RETURN",
                "BREAK", "GOTO", "REVERT", "BROWSE", "GRANT", "REVOKE", "BULK", "GROUP", "RIGHT", "BY", "HAVING", "ROLLBACK", "CASCADE", "HOLDLOCK", "ROWCOUNT", "CASE", "IDENTITY", "ROWGUIDCOL",
                "CHECK", "IDENTITY_INSERT", "RULE", "CHECKPOINT", "IDENTITYCOL", "SAVE", "CLOSE", "IF", "SCHEMA", "CLUSTERED", "IN", "SECURITYAUDIT", "COALESCE", "INDEX", "SELECT",
                "COLLATE", "INNER", "SEMANTICKEYPHRASETABLE", "COLUMN", "INSERT", "SEMANTICSIMILARITYDETAILSTABLE", "COMMIT", "INTERSECT", "SEMANTICSIMILARITYTABLE",
                "COMPUTE", "INTO", "SESSION_USER", "CONSTRAINT", "IS", "SET", "CONTAINS", "JOIN", "SETUSER", "CONTAINSTABLE", "KEY", "SHUTDOWN", "CONTINUE", "KILL", "SOME",
                "CONVERT", "LEFT", "STATISTICS", "CREATE", "LIKE", "SYSTEM_USER", "CROSS", "LINENO", "TABLE", "CURRENT", "LOAD", "TABLESAMPLE", "CURRENT_DATE", "MERGE", "TEXTSIZE",
                "CURRENT_TIME", "NATIONAL", "THEN", "CURRENT_TIMESTAMP", "NOCHECK", "TO", "CURRENT_USER", "NONCLUSTERED", "TOP", "CURSOR", "NOT", "TRAN", "DATABASE", "NULL", "TRANSACTION",
                "DBCC", "NULLIF", "TRIGGER", "DEALLOCATE", "OF", "TRUNCATE", "DECLARE", "OFF", "TRY_CONVERT", "DEFAULT", "OFFSETS", "TSEQUAL", "DELETE", "ON", "UNION", "DENY", "OPEN", "UNIQUE",
                "DESC", "OPENDATASOURCE", "UNPIVOT", "DISK", "OPENQUERY", "UPDATE", "DISTINCT", "OPENROWSET", "UPDATETEXT", "DISTRIBUTED", "OPENXML", "USE", "DOUBLE", "OPTION", "USER",
                "DROP", "Or", "VALUES", "DUMP", "ORDER", "VARYING", "ELSE", "OUTER", "VIEW", "END", "OVER", "WAITFOR", "ERRLVL", "PERCENT", "WHEN", "ESCAPE", "PIVOT", "WHERE", "EXCEPT", "PLAN", "WHILE",
                "EXEC", "PRECISION", "WITH", "EXECUTE", "PRIMARY", "WITHIN GROUP", "EXISTS", "PRINT", "WRITETEXT", "EXIT", "PROC", "CREATE PROCEDURE", "NOCOUNT", "COUNT"}
Dim srv As Server
Dim name As String
Dim db As Database
Dim sp As StoredProcedure

Private Sub Admin_Props_Load(sender As Object, e As EventArgs) Handles Me.Load
    openDB()
    db = srv.Databases(databaseName)
    If Len(Request.QueryString("name")) = 0 Then
        lblData.Text = "Not a valid StoredProcedure"
    Else
        sp = db.StoredProcedures(Request.QueryString("name").ToString)
        lblData.Text = addHighlight(sp.TextBody)
    End If
End Sub
Sub openDB()
    Dim sqlConn As New SqlConnection("Data Source=xxxx;Integrated Security=True;")
    Dim SerCon As New Microsoft.SqlServer.Management.Common.ServerConnection(sqlConn)
    srv = New Server(SerCon)
End Sub

Function addHighlight(ByVal strIn As String) As String

    Dim keyWords As Array = searchArr
    Dim keyInd As Integer
    Dim str2() As String
    str2 = strIn.Split(" ")
    If Len(Trim(strIn)) > 0 And IsArray(keyWords) Then
        For keyInd = LBound(keyWords) To UBound(keyWords)
            For i As Integer = LBound(str2) To UBound(str2)
                str2(i) = Replace(str2(i), UCase(keyWords(keyInd)), "*|*" & UCase(keyWords(keyInd)) & "*||*", 1, -1, 1)
                'strIn = Replace(strIn, UCase(keyWords(keyInd)), "*|*" & UCase(keyWords(keyInd)) & "*||*", 1, -1, 1)
            Next
        Next
    End If
    strIn = Join(str2, " ")
    strIn = Replace(strIn, Chr(13), "<br>", 1, -1, 1)
    strIn = Replace(strIn, "*|*", "<span class=""Highlight"">")
    strIn = Replace(strIn, "*||*", "</span>")
    addHighlight = strIn
End Function

当我 运行 这样做时,我得到了颜色格式的混合结果,因为替换不仅会得到整个单词,还会得到更大单词的子字符串;这不应该发生。 结果应该是这样的;

CREATE PROCEDURE AddCityToList 
    -- Add the parameters for the stored procedure here
    @idCity int, 
    @idProduct int
AS
BEGIN
    -- SET NOCOUNT ON added to prevent extra result sets from
    -- interfering with SELECT statements.
    SET NOCOUNT ON;

    -- Insert statements for procedure here
    INSERT INTO CityProductExclude (idCity,idProduct)
    VALUES (@idCity,@idProduct)

END

没有在备注中的关键字应该突出显示并大写,我怎么得到以下回复;

-- =============================================
-- AuthOR: OR,,Name>
-- CREATE date: <CREATE Date,,>
-- DESCriptiON: <DESCriptiON,,>
-- =============================================
CREATE PROCEDURE ADDCityTOLISt
-- ADD the parameters FOR the sTOred PROCEDURE here
@idCity INt,
@idProduct INt
AS
BEGIN
-- SET NOCOUNT ON ADDed TO prevent extra result SETs FROM
-- INterferINg WITH SELECT statements.
SET NOCOUNT ON;

-- INsert statements FOR PROCEDURE here
INSERT INTO CityProductExclude (idCity,idProduct)
VALUES (@idCity,@idProduct)

END

我错过了什么?任何帮助将不胜感激

考虑 sp.TextBody 是一个长字符串,包含带有换行符的存储过程命令,用空格分割可能不是区分 SQL 关键字和评论部分的好方法,因此最好根据分割从换行符出现:

str2 = strIn.Split(New String() { Environment.NewLine }, StringSplitOptions.None)

通过使用上面的赋值,它能够检测任何以 -- 开头的字符串作为 SQL 注释并保持它们完整,因此使用 Regex.Replace 方法可以大写任何确切的 SQL 未标记为评论的关键词:

' Notes:
' (1) Using System.Text.RegularExpressions required to call Regex.Replace
' (2) StartsWith used to detect comment section in stored procedure body
' (3) "\b" + keyWords(keyInd) + "\b" used to replace by whole keywords only

If Len(Trim(strIn)) > 0 And IsArray(keyWords) Then
    For keyInd = LBound(keyWords) To UBound(keyWords)
        For i As Integer = LBound(str2) To UBound(str2)
            If Not str2(i).StartsWith("--")
                str2(i) = Regex.Replace(str2(i), "\b" + keyWords(keyInd) + "\b", "*|*" & UCase(keyWords(keyInd)) & "*||*", RegexOptions.IgnoreCase)
            End If
        Next
    Next
End If

然后,将所有内容放在 addHighlight 函数中:

Function addHighlight(ByVal strIn As String) As String
    Dim keyWords As Array = searchArr
    Dim keyInd As Integer
    Dim str2() As String
    str2 = strIn.Split(New String() { Environment.NewLine }, StringSplitOptions.None)
    If Len(Trim(strIn)) > 0 And IsArray(keyWords) Then
        For keyInd = LBound(keyWords) To UBound(keyWords)
            For i As Integer = LBound(str2) To UBound(str2)
                If Not str2(i).StartsWith("--")
                    str2(i) = Regex.Replace(str2(i), "\b" + keyWords(keyInd) + "\b", "*|*" & UCase(keyWords(keyInd)) & "*||*", RegexOptions.IgnoreCase)
                End If
            Next
        Next
    End If
    strIn = Join(str2, Environment.NewLine)
    strIn = Replace(strIn, Chr(13), "<br />", 1, -1, 1)
    strIn = Replace(strIn, "*|*", "<span class=""Highlight"">")
    strIn = Replace(strIn, "*||*", "</span>")
    addHighlight = strIn
End Function

注意:要使这个技巧起作用,请设置 strIn 内容以在注释符号前包含换行符,如下所示(仅当 T-SQL 字符串在注释前不包含换行符时使用):

If Not strIn.Contains(Environment.NewLine) Then
    strIn = Replace(strIn, "--", Environment.NewLine & "--")
End If

演示:.NET Fiddle Example

相关:

Way to have String.Replace only hit "whole words"