【问题标题】:.NET / Oracle: How to execute a script with DDL statements programmatically.NET / Oracle:如何以编程方式使用 DDL 语句执行脚本
【发布时间】:2013-07-17 12:24:01
【问题描述】:

我想在 C# 中对 oracle 数据库进行一些编程模式操作。因此,我在一些基本问题上苦苦挣扎。

ddl sql 语句位于脚本文件中。我不想使用 sqlplus.exe,但我想使用 ODP.NET 程序集 (System.Oracle.DataAccess) 之外的 OracleCommand。这是我的脚本文件的示例:

脚本.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 错误:

Oracle.DataAccess.Client.OracleException:ORA-00911:无效字符

我认为,语句的格式可能存在一些问题。任何提示表示赞赏。谢谢。

---编辑---

用一种简单的方式总结我的需求:我寻找一种方法来执行任何 sql/ddl 脚本,该脚本可由 SQL Plus 执行,使用 C# 以编程方式。

【问题讨论】:

  • 更新:我试图用“DECLARE BEGIN EXECUTE IMMEDIATE '....' END;”来包装脚本的内容。因为这应该有助于 DDL 语句,但没有运气,同样的错误消息

标签: c# oracle ddl


【解决方案1】:

感谢分号提示

我运行 oracle 脚本的最终代码!

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;
        }
    }

【讨论】:

    【解决方案2】:

    只需将其包裹在 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();
      }
    }
    

    【讨论】:

    • 你不能简单地在 SQL 脚本中移动那些吗?
    • 当然可以,不过这只是为了演示!
    【解决方案3】:

    正如@Steve 所说,分号导致您的错误。而且您不能将整个文件包装到单个 execute immediate 命令中,因为它一次只能执行一个语句。您将需要解析您的文件并自行执行每个命令,删除用于划分命令的分号。正如您所指出的,您的解析必须处理字符串文字,除了包含分号外,还可能在开始和结束字符串文字的单引号 (') 中包含双引号 ('')。

    【讨论】:

      【解决方案4】:

      我会尝试一次执行一行,看看你是否有任何奇怪的字符阻止执行。 (我也不确定您是否可以通过一次通话将所有命令一起发送)。

      您还应该删除行尾的分号

      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);
      }
      

      【讨论】:

      • 谢谢。这种方法的问题是文字中可能包含分号 - 这会破坏长脚本。
      • 所以你是说你有一个多行的脚本?脚本之间没有可识别的分隔符?然后你需要以某种方式拆分你的输入,因为我很确定用作单个命令的闭包的分号是错误的原因
      • 我不确定您所说的“多行单个脚本”是什么意思。但是我会有比一行长的“创建表”语句。我终于需要一种机制来执行与 SQLPlus 一起运行的相同脚本而不会出现问题。
      • 如果你有超过一行的“命令”以及引号内带有分号的文本文字,那么唯一可能的解决方案是逐行解析以删除末尾的分号“命令”,但不是文本文字内的命令。这不是一件容易的事,你仍然需要分开传递每个“命令”。我没有要测试的 Oracle 安装,但是在开始解析之前,我将尝试一个简单的文件 sql,其中只有一个以分号结尾的命令,然后没有分号,只是为了检查有无分号的区别
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-01-02
      • 2011-05-28
      • 1970-01-01
      • 1970-01-01
      • 2020-09-27
      • 1970-01-01
      • 2017-12-18
      相关资源
      最近更新 更多