1

我对 sql 还很陌生,并且在我的 sql 脚本中遇到了导致严重破坏的关键字的问题。我正在尝试在 C# 中执行预制的 .sql 脚本文件列表。我目前正在将文件读取为字符串并使用 command.ExecuteNonQuery() 执行它。这适用于大多数脚本,但我遇到了一个无意中包含关键字的脚本:

INSERT INTO [thetable]
SELECT '123123', 'abcabc', 'I WANT TO GO TO BED'
UNION ALL
SELECT '123124', 'abcdef', 'SOOO TIRED'

本质上,当它命中 GO 时,命令会失败。

我负责创建这些插入文件,所以如果我需要以某种方式重新格式化它们,那是可能的;但是,其中的数据是不可协商的。此外,由于我是从包含许多行的文件中加载它们,因此避免这些东西的参数化似乎也不可行。

在这一点上,任何帮助将不胜感激。非常感谢!

编辑以添加信息:

澄清一下,实际的字符串更像是“ASVFDS4+23eF3da34sddsdf3d3t4g...100charslater...sd5OAyGOsiISIssdsd/sNUIGsdisd354f”。当我尝试执行命令时,我捕获了异常,它说:

"Unclosed quotation mark after character string 'ASVFDS4+23eF3da34sddsdf3d3t4g...100charslater...sd5OAy'

请注意,5OAy 紧随其后的是 GOsiIS...,这让我相信 GO 实际上是作为命令读取的,导致它期望在该命令之前结束字符串。

运行 .NET 3.5

编辑 2 我还应该澄清一下,我目前正在拆分实际的 GO 语句并单独执行命令。

IE

USE MyDatabase
GO
INSERT INTO [thetable]
SELECT '123123', 'abcabc', 'I WANT TO GO TO BED'
UNION ALL
SELECT '123124', 'abcdef', 'SOOO TIRED'
UNION ALL
...
SELECT '123189', 'abcabc', 'HAD SOME SLEEP'
GO

分裂,所以我执行

USE MyDatabase

INSERT INTO [thetable]
SELECT '123123', 'abcabc', 'I WANT TO GO TO BED'
UNION ALL
SELECT '123124', 'abcdef', 'SOOO TIRED'
UNION ALL
...
SELECT '123189', 'abcabc', 'HAD SOME SLEEP'

分别地。所以我的问题不在于实际的 GO 语句,而在于数据字符串中出现的字符“GO”。

回答:问题是我犯了一个非常愚蠢的错误。我在“GO”上拆分,它将命令字符串拆分在该参数中间出现字母 GO 的位置​​。

/掌脸

感谢所有的帮助!

4

2 回答 2

4

如果您需要使用 'go' ("smth go smth") 等解析任何带有注释和字符串值的 Sql 脚本,您可以使用gplex工具。sql脚本解析的Gplex规则:

%namespace LexScanner
%option verbose, summary, noparser, unicode

%x QUOTE
%x COMMENT

%{
    static string line = "";
    static List<string> butch = new List<string>();
    enum TokenType {
        SL_COMMENT,
        ML_COMMENT,
        STRING,
        WORD,
        OTHER,
        ending
    };
%}

dotchr [^\r\n] 
eol (\r\n?|\n)
%%
\-\-[^\n]*$             { add(yytext, TokenType.SL_COMMENT); }

\/\*                    { add(yytext, TokenType.ML_COMMENT); BEGIN(COMMENT); }
<COMMENT>\*\/           { add(yytext, TokenType.ML_COMMENT); BEGIN(INITIAL); }
<COMMENT>[^\*]+         { add(yytext, TokenType.ML_COMMENT); }
<COMMENT>\*             { add(yytext, TokenType.ML_COMMENT); }

\'                      { add(yytext, TokenType.STRING); BEGIN(QUOTE); }
<QUOTE>\'\'             { add(yytext, TokenType.STRING); }
<QUOTE>[^\']+           { add(yytext, TokenType.STRING); }
<QUOTE>\'               { add(yytext, TokenType.STRING); BEGIN(INITIAL); }

[gG][oO]                { push(); }

[a-zA-Z0-9]+            { add(yytext, TokenType.WORD); }
.                       { add(yytext, TokenType.OTHER); }
\r?\n                   { add(yytext, TokenType.OTHER); }
<<EOF>>                 { push(); }
%%

然后生成 C# 类并使用它。

编辑:
更多评论如何使用它。
函数add(string text, TokenType token)push()- 如何处理已解析的字符串。add() 函数收集 GO 关键字之间的解析字符串并将结果写入输出文件(仅用于控制):

private void add(string text, TokenType token)
{
    //write to the file for output control (for test only)
    using (StreamWriter str = new StreamWriter("C:\\temp\\temp.txt", true))
    {
        str.WriteLine(token + " : " + text); 
    }
    line += text;
}

push() 收集执行的字符串:

private void push()
{
    //write to the file for output control (for test only)
    using (StreamWriter str = new StreamWriter("C:\\temp\\butch.txt", true))
    {
        str.WriteLine("GO: " + line); 
    }

    butch.Add(line);
    line = "";
}

要从 C# 代码中使用此类,您应该指定入口点。例如:

 public static List<string> ParseFile(String fileToParse)
 {
     int tok;
     Scanner scnr = new Scanner();
     scnr.SetSource(fileToParse, 0);
     do {
             tok = scnr.yylex();
         } while (tok > (int)Tokens.EOF);
     return butch;
 }

或者定义一个 Main 函数将其用作独立应用程序。

上述所有代码都应放在 .lex 文件中。文件 sqlparser.cs 是通过从命令行调用创建的:

gplex sqlparser.lex

Gplex 有一个很好的文档和示例如何使用它。

于 2012-03-27T15:12:02.597 回答
1

You need to recognise the GO yourself, and use it to split the file up into batches, then execute each one individually.

Use a regex something like m/^\s+GO\s+$/i to recognise the GO lines.

于 2012-03-27T09:51:13.447 回答