Ключевые слова в данных сценария SQL, вызывающие проблемы при программном выполнении - C#
Я довольно новичок в SQL и имею проблему с ключевыми словами, вызывающими хаос в моем сценарии SQL. Я пытаюсь выполнить список готовых файлов сценариев.sql в C#. В настоящее время я читаю файл в строку и выполняю его с помощью 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 операторов и выполнения команд по отдельности.
т.е.
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.
/ Facepalm
Спасибо за помощь!
2 ответа
Вы должны распознать GO самостоятельно и использовать его, чтобы разбить файл на пакеты, а затем выполнить каждый в отдельности.
Используйте регулярные выражения, например, m/^\s+GO\s+$/i, чтобы распознать строки GO.
Если вам нужно проанализировать любые сценарии Sql с комментариями и строковыми значениями с помощью 'go' ("smth go smth") и т. Д., Вы можете использовать инструмент gplex. Правила Gplex для разбора скриптов sql:
%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 имеет хорошую документацию и примеры, как ее использовать.