.NET/Oracle: как программно выполнить сценарий с операторами DDL

Я хочу выполнить некоторые программные манипуляции со схемой в базе данных оракула на С#. Поэтому я борюсь с некоторыми основными проблемами.

Операторы ddl sql находятся в файле сценария. Я не хочу использовать sqlplus.exe, но хочу использовать OracleCommand из сборок ODP.NET (System.Oracle.DataAccess). Вот пример моего файла сценария:

скрипт.sql:

DROP TABLE ABCDEF; 

DROP TABLE GHIJKL;

Я хочу отметить:

  • Сценарий содержит операторы DDL (язык определения данных)
  • Скрипт содержит пустые строки
  • Сценарий содержит более одного оператора.

Следующий код должен выполнить мой скрипт:

var content = File.ReadAllText("script.sql");

using (var oracleConnection = new OracleConnection(_connectionString))
{
     oracleConnection.Open();

     using (var command = new OracleCommand(content) { Connection = oracleConnection })
     {
          command.CommandType = CommandType.Text;
          command.ExecuteNonQuery();
     }
}

Выполняя этот код, я получаю ошибку оракула:

Oracle.DataAccess.Client.OracleException: ORA-00911: недопустимый символ

Я думаю, может быть, есть какая-то проблема с форматированием утверждений. Любая подсказка приветствуется. Спасибо.

---ИЗМЕНИТЬ---

Подводя итог моим потребностям простым способом: я ищу подход для выполнения любого сценария sql/ddl, который выполняется SQL Plus, программно с помощью C#.


person user2516186    schedule 18.07.2013    source источник
comment
ОБНОВЛЕНИЕ: я попытался обернуть содержимое сценария с помощью DECLARE BEGIN EXECUTE IMMEDIATE '....' END; так как это должно помочь с операторами DDL, но не повезло, то же сообщение об ошибке   -  person user2516186    schedule 18.07.2013


Ответы (4)


Как сказал @Steve, точка с запятой вызывает вашу ошибку. И вы не можете обернуть весь файл в одну команду execute immediate, так как она может выполнять только один оператор за раз. Вам нужно будет разобрать файл и выполнить каждую команду отдельно, удалив точку с запятой, разделяющую команды. Как вы заметили, ваш синтаксический анализ должен будет иметь дело со строковыми литералами, которые помимо содержания точек с запятой могут также содержать двойные одинарные кавычки ('') в одинарных кавычках ('), которые начинают и заканчивают строковый литерал.

person GriffeyDog    schedule 18.07.2013

Просто оберните его внутри BEGIN и END, и он будет работать гладко.

var content =string.Format("BEGIN {0} END;", File.ReadAllText("script.sql"));
using (var oracleConnection = new OracleConnection(_connectionString))            
{
  oracleConnection.Open();
  using (var command = new OracleCommand(content) { Connection = oracleConnection })
  {
       command.CommandType = CommandType.Text;
       command.ExecuteNonQuery();
  }
}
person Anwer Matter    schedule 18.03.2015
comment
не могли бы вы просто переместить их внутри скрипта SQL? - person Helbo; 15.05.2016
comment
Конечно, вы можете, это только для демонстрации! - person Anwer Matter; 22.11.2016

Спасибо за совет с точкой с запятой!

Мой окончательный код для запуска сценариев оракула!

1) Он принимает: - пустые строки/комментарии ( -- ) строки - многострочные команды DDl/DML, оканчивающиеся на ;

2) В случае ошибки выдает исключение с номером строки и командой sql!

    public async Task ExecuteScript(string _connectionString, string script)
    {
        using (StringReader sr = new StringReader(script))
        {
            var connection = new OracleConnection(_connectionString);
            connection.Open();

            string sqlCommand = "";
            string sqlLine; byte lineNum = 0;

            while ((sqlLine = sr.ReadLine()) != null)
            {
                sqlLine = sqlLine.Trim(); ++lineNum;

                if (sqlLine.Length > 0 && !sqlLine.StartsWith("--"))
                {
                     sqlCommand += (sqlCommand.Length > 0 ? Environment.NewLine : "") + sqlLine;  // Accept multiline SQL

                    if (sqlCommand.EndsWith(";"))
                    {
                        sqlCommand = sqlCommand.Substring(0, sqlCommand.Length - 1);

                        var command = new OracleCommand(sqlCommand, connection);

                        try
                        {
                            await command.ExecuteNonQueryAsync(); 
                        }
                        catch (OracleException ex)
                        {
                            connection.Close();
                            var e2 = new Exception($"{lineNum} - {sqlCommand} <br/> {ex.Message}");
                            throw e2;
                        }
                    }
                }
            }

            connection.Close();

            return;
        }
    }
person Marco Rodrigues    schedule 28.02.2020

Я попытаюсь выполнить по одной строке, чтобы увидеть, есть ли у вас какой-нибудь странный символ, который блокирует выполнение. (Я также не уверен, сможете ли вы отправить все свои команды вместе всего за один вызов).

Также вам необходимо удалить точку с запятой в конце строк.

int lineNum = 0;
try
{
    string[] cmdTexts = File.ReadAllLines("script.sql");

    using (var oracleConnection = new OracleConnection(_connectionString))
    {
         oracleConnection.Open();
         OracleCommand command = new OracleCommand();
         command.Connection = oracleConnection;
         foreach(string cmd in cmdTexts)
         {
              lineNum++;
              if(cmd.Trim().Length > 0)
              {
                  if(cmd.EndsWith(";"))
                      cmd = cmd.Substring(0, cmd.Length - 1);

                  command.CommandText = cmd;
                  command.ExecuteNonQuery();
              }
         }
    }
}
catch(Exception ex)
{
    MessageBox.Show("Exception on line: " + lineNum + " message: " + ex.Message);
}
person Steve    schedule 18.07.2013
comment
Спасибо. Проблема с этим подходом заключается в том, что в литералах могут содержаться точки с запятой, что разбивает длинные сценарии. - person user2516186; 18.07.2013
comment
Так вы говорите, что у вас есть один сценарий на несколько строк? Без узнаваемого разделителя между скриптами? Затем вам нужно каким-то образом разделить ваши входные данные, потому что я уверен, что точка с запятой, используемая как закрытие одной команды, является причиной ошибки - person Steve; 18.07.2013
comment
Я не уверен, что вы имеете в виду под одним скриптом в нескольких строках. Но у меня будут операторы «создать таблицу», которые длиннее одной строки. Наконец-то мне нужен механизм для выполнения тех же скриптов, которые работают с SQLPlus без проблем. - person user2516186; 18.07.2013
comment
Если у вас есть «команды», которые распространяются более чем на одну строку, а также текстовые литералы с точками с запятой внутри кавычек, то единственным возможным решением является разбор строки за строкой для удаления точек с запятой в конце «команд», но не те которые находятся внутри текстовых литералов. Непростая задача, и все же вам нужно передать каждую «команду» отдельно. У меня нет установки Oracle для тестирования, но перед тем, как начать синтаксический анализ, я попробую простой файл sql с одной командой, заканчивающейся точкой с запятой, а затем без точки с запятой, чтобы проверить разницу с точкой с запятой или без нее. - person Steve; 18.07.2013