[C#] C #을 사용하여 .SQL 스크립트 파일을 실행하는 방법

이 질문에 이미 답변이 되었음에도 불구하고 검색 도구를 사용하여 답변을 찾을 수 없습니다.

C #을 사용하여 .sql 파일을 실행하고 싶습니다. sql 파일에는 여러 개의 sql 문이 포함되어 있으며 일부는 여러 줄로 나뉩니다. 파일을 읽고 ODP.NET을 사용하여 파일을 실행하려고 시도했지만 … ExecuteNonQuery가 실제로이 작업을 수행한다고 생각하지 않습니다.

따라서 프로세스 생성을 통해 sqlplus를 사용해 보았습니다 …하지만 UseShellExecute가 true로 설정된 프로세스를 생성하지 않으면 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의 부작용은 리디렉션 된 출력을 캡처 할 수 없다는 것입니다.



답변

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로 시도했지만 .NET 4.0에서는 제대로 작동하지 않으므로 .NET libs 프레임 워크만을 사용하여 다른 솔루션을 작성했습니다.

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 (!string.IsNullOrWhiteSpace(commandString.Trim()))
    {
        using(var command = new SqlCommand(commandString, Connection))
        {
            command.ExecuteNonQuery();
        }
    }
}
Connection.Close();


답변

이것은 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;
        }
    }


답변

SQL 스크립트를 배치 파일로 실행하는 명령을 넣고 아래 코드를 실행하십시오.

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 )

배치 파일에서 다음과 같이 작성하십시오 (SQL 서버의 샘플)

osql -E -i %1


답변

이것은 나를 위해 작동합니다 :

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


답변

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

C : \ Program Files \ Microsoft SQL Server에 여러 폴더가 있기 때문에 올바른 dll : s인지는 모르겠지만 내 응용 프로그램에서는이 두 가지가 작동합니다.


답변

나는 매뉴얼을 읽음으로써 대답을 해결할 수 있었다 🙂

MSDN에서 추출

코드 예제는 p.WaitForExit 전에 p.StandardOutput.ReadToEnd를 호출하여 교착 상태를 방지합니다. 부모 프로세스가 p.StandardOutput.ReadToEnd 전에 p.WaitForExit를 호출하고 자식 프로세스가 리디렉션 된 스트림을 채우기에 충분한 텍스트를 쓰면 교착 상태가 발생할 수 있습니다. 부모 프로세스는 자식 프로세스가 종료 될 때까지 무기한 대기합니다. 자식 프로세스는 부모가 전체 StandardOutput 스트림에서 읽을 때까지 무기한 대기합니다.

표준 출력 및 표준 오류 스트림에서 모든 텍스트를 읽을 때 비슷한 문제가 있습니다. 예를 들어 다음 C # 코드는 두 스트림 모두에서 읽기 작업을 수행합니다.

코드를 이것으로 바꿉니다.

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

이제 올바르게 종료됩니다.