如何使用c#执行.SQL脚本文件

我相信这个问题已经被回答了,但是我找不到使用search工具的答案。

使用C#我想运行一个.sql文件。 该sql文件包含多个sql语句,其中一些被分成多行。 我尝试阅读文件,并尝试使用ODP.NET执行文件…但是我不认为ExecuteNonQuery是真的devise来做到这一点。

所以我尝试通过产生一个进程使用sqlplus …但是,除非我用UseShellExecute设置为真的产生的进程sqlplus将挂起,永远不会退出。 这是不起作用的代码。

Process p = new Process(); p.StartInfo.UseShellExecute = false; p.StartInfo.RedirectStandardOutput = true; p.StartInfo.FileName = "sqlplus"; p.StartInfo.Arguments = string.Format("xx/xx@{0} @{1}", in_database, s); p.StartInfo.CreateNoWindow = true; bool started = p.Start(); p.WaitForExit(); 

WaitForExit永远不会返回….除非我将UseShellExecute设置为true。 UseShellExecute的副作用是你不能捕获redirect的输出。

 using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.UI; using System.Web.UI.WebControls; using Microsoft.SqlServer.Management.Smo; using Microsoft.SqlServer.Management.Common; using System.IO; using System.Data.SqlClient; public partial class ExcuteScript : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { string sqlConnectionString = @"Integrated Security=SSPI;Persist Security Info=False;Initial Catalog=ccwebgrity;Data Source=SURAJIT\SQLEXPRESS"; string script = File.ReadAllText(@"E:\Project Docs\MX462-PD\MX756_ModMappings1.sql"); SqlConnection conn = new SqlConnection(sqlConnectionString); Server server = new Server(new ServerConnection(conn)); server.ConnectionContext.ExecuteNonQuery(script); } } 

我用Microsoft.SqlServer.Management尝试了这个解决scheme,但是它不能很好地处理.NET 4.0,所以我只写了另一个使用.NET libs框架的解决scheme。

  string script = File.ReadAllText(@"E:\someSqlScript.sql"); // split script on GO command IEnumerable<string> commandStrings = Regex.Split(script, @"^\s*GO\s*$", RegexOptions.Multiline | RegexOptions.IgnoreCase); Connection.Open(); foreach (string commandString in commandStrings) { if (commandString.Trim() != "") { using(var command = new SqlCommand(commandString, Connection)) { command.ExecuteNonQuery(); } } } Connection.Close(); 

把命令执行sql脚本到一个batch file,然后运行下面的代码

 string batchFileName = @"c:\batosql.bat"; string sqlFileName = @"c:\MySqlScripts.sql"; Process proc = new Process(); proc.StartInfo.FileName = batchFileName; proc.StartInfo.Arguments = sqlFileName; proc.StartInfo.WindowStyle = ProcessWindowStyle.Hidden; proc.StartInfo.ErrorDialog = false; proc.StartInfo.WorkingDirectory = Path.GetDirectoryName(batchFileName); proc.Start(); proc.WaitForExit(); if ( proc.ExitCode!= 0 ) 

在batch file中写入这样的东西(示例为SQL服务器)

 osql -E -i %1 

我设法通过阅读手册来解决答案:)

这是从MSDN提取的

代码示例通过在p.WaitForExit之前调用p.StandardOutput.ReadToEnd来避免死锁情况。 如果父进程在p.StandardOutput.ReadToEnd之前调用p.WaitForExit并且subprocess写入足够的文本以填充redirect的stream,则可能会导致死锁情况。 父进程将无限期地等待subprocess退出。 subprocess将无限期等待父进程从完整的StandardOutputstream中读取。

从标准输出和标准错误stream中读取所有文本时,也有类似的问题。 例如,以下C#代码在两个stream上执行读取操作。

将代码转换成这个;

 Process p = new Process(); p.StartInfo.UseShellExecute = false; p.StartInfo.RedirectStandardOutput = true; p.StartInfo.FileName = "sqlplus"; p.StartInfo.Arguments = string.Format("xxx/xxx@{0} @{1}", in_database, s); bool started = p.Start(); // important ... read stream input before waiting for exit. // this avoids deadlock. string output = p.StandardOutput.ReadToEnd(); p.WaitForExit(); Console.WriteLine(output); if (p.ExitCode != 0) { Console.WriteLine( string.Format("*** Failed : {0} - {1}",s,p.ExitCode)); break; } 

哪个现在退出正确。

添加额外的改进surajits回答:

 using System; using Microsoft.SqlServer.Management.Smo; using Microsoft.SqlServer.Management.Common; using System.IO; using System.Data.SqlClient; namespace MyNamespace { public partial class RunSqlScript : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { var connectionString = @"your-connection-string"; var pathToScriptFile = Server.MapPath("~/sql-scripts/") + "sql-script.sql"; var sqlScript = File.ReadAllText(pathToScriptFile); using (var connection = new SqlConnection(connectionString)) { var server = new Server(new ServerConnection(connection)); server.ConnectionContext.ExecuteNonQuery(sqlScript); } } } } 

此外,我不得不添加以下引用到我的项目:

  • C:\Program Files\Microsoft SQL Server\120\SDK\Assemblies\Microsoft.SqlServer.ConnectionInfo.dll
  • C:\Program Files\Microsoft SQL Server\120\SDK\Assemblies\Microsoft.SqlServer.Smo.dll

我不知道是否这些是正确的DLL使用,因为在C:\ Program Files \ Microsoft SQL Server中有几个文件夹,但在我的应用程序中这两个工作。

这适用于Framework 4.0或更高版本。 支持“GO”。 同时显示错误消息,行和sql命令。

 using System.Data.SqlClient; private bool runSqlScriptFile(string pathStoreProceduresFile, string connectionString) { try { string script = File.ReadAllText(pathStoreProceduresFile); // split script on GO command System.Collections.Generic.IEnumerable<string> commandStrings = Regex.Split(script, @"^\s*GO\s*$", RegexOptions.Multiline | RegexOptions.IgnoreCase); using (SqlConnection connection = new SqlConnection(connectionString)) { connection.Open(); foreach (string commandString in commandStrings) { if (commandString.Trim() != "") { using (var command = new SqlCommand(commandString, connection)) { try { command.ExecuteNonQuery(); } catch (SqlException ex) { string spError = commandString.Length > 100 ? commandString.Substring(0, 100) + " ...\n..." : commandString; MessageBox.Show(string.Format("Please check the SqlServer script.\nFile: {0} \nLine: {1} \nError: {2} \nSQL Command: \n{3}", pathStoreProceduresFile, ex.LineNumber, ex.Message, spError), "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); return false; } } } } connection.Close(); } return true; } catch (Exception ex) { MessageBox.Show(ex.Message, "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); return false; } } 

这适用于我:

 public void updatedatabase() { SqlConnection conn = new SqlConnection("Data Source=" + txtserver.Text.Trim() + ";Initial Catalog=" + txtdatabase.Text.Trim() + ";User ID=" + txtuserid.Text.Trim() + ";Password=" + txtpwd.Text.Trim() + ""); try { conn.Open(); string script = File.ReadAllText(Server.MapPath("~/Script/DatingDemo.sql")); // split script on GO command IEnumerable<string> commandStrings = Regex.Split(script, @"^\s*GO\s*$", RegexOptions.Multiline | RegexOptions.IgnoreCase); foreach (string commandString in commandStrings) { if (commandString.Trim() != "") { new SqlCommand(commandString, conn).ExecuteNonQuery(); } } lblmsg.Text = "Database updated successfully."; } catch (SqlException er) { lblmsg.Text = er.Message; lblmsg.ForeColor = Color.Red; } finally { conn.Close(); } } 

有两点需要考虑。

1)这个源代码为我工作:

 private static string Execute(string credentials, string scriptDir, string scriptFilename) { Process process = new Process(); process.StartInfo.UseShellExecute = false; process.StartInfo.WorkingDirectory = scriptDir; process.StartInfo.RedirectStandardOutput = true; process.StartInfo.FileName = "sqlplus"; process.StartInfo.Arguments = string.Format("{0} @{1}", credentials, scriptFilename); process.StartInfo.CreateNoWindow = true; process.Start(); string output = process.StandardOutput.ReadToEnd(); process.WaitForExit(); return output; } 

我将工作目录设置为脚本目录,以便脚本中的子脚本也可以工作。

把它叫做Execute("usr/pwd@service", "c:\myscripts", "script.sql")

2)你必须用EXIT;语句来完成你的SQL脚本EXIT;