bestsource

실행 방법c#을 사용한SQL 스크립트파일

bestsource 2023. 3. 15. 19:49
반응형

실행 방법c#을 사용한SQL 스크립트파일

이 질문에 대한 답변은 이미 완료되었지만 검색 도구를 사용하여 답변을 찾을 수 없었습니다.

c#을 사용하여 .sql 파일을 실행하고 싶습니다.sql 파일에는 여러 개의 sql 문이 포함되어 있으며, 그 중 일부는 여러 줄로 구분되어 있습니다.파일을 읽어보고 ODP를 사용하여 실행해 보았습니다.NET... 하지만 Execute Non Query가 실제로 이 기능을 수행하도록 설계되어 있다고는 생각하지 않습니다.

sqlplus를 사용하여 프로세스를 산란해 보았습니다.그러나 UseShell Execute가 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();

Wait For Exit이 반환되지 않음...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);
    }
}

이 솔루션을 마이크로소프트와 함께 사용해 보았습니다.SqlServer.관리. 하지만 와는 잘 되지 않았다.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;
                            }
                        }
                    }
                }
            }
            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를 사용하는 것이 적절한지 여부를 알 수 없습니다만, 어플리케이션에서는 이 2개가 동작합니다.

매뉴얼을 읽고 겨우 답을 알아냈습니다.

MSDN에서 발췌한 내용입니다.

코드 예에서는 p를 호출하여 교착 상태를 회피합니다.표준 출력읽기 전 종료.Wait For Exit(종료 대기부모 프로세스가 p를 호출하면 교착 상태가 발생할 수 있습니다.p 전에 Wait For Exit.표준 출력ReadToEnd 및 자식 프로세스는 리디렉션된 스트림을 채우기에 충분한 텍스트를 씁니다.부모 프로세스는 자식 프로세스가 종료될 때까지 무기한 대기합니다.자식 프로세스는 부모가 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;
}

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

고려해야 할 점이 두 가지 있습니다.

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)를 2) SQL 스크립트로 .EXIT;

Entity Framework를 사용하면 다음과 같은 솔루션을 사용할 수 있습니다.이 코드를 사용하여 e2e 테스트를 초기화합니다.SQL 주입 공격을 방지하려면 사용자 입력에 따라 이 스크립트를 생성하거나 이 스크립트에 명령 매개 변수를 사용하지 마십시오( 매개 변수를 받아들이는 ExecuteSqlCommand 오버로드 참조).

public static void ExecuteSqlScript(string sqlScript)
{
    using (MyEntities dataModel = new MyEntities())
    {
        // split script on GO commands
        IEnumerable<string> commands = 
            Regex.Split(
                sqlScript, 
                @"^\s*GO\s*$",
                RegexOptions.Multiline | RegexOptions.IgnoreCase);

        foreach (string command in commands)
        {
            if (command.Trim() != string.Empty)
            {
                dataModel.Database.ExecuteSqlCommand(command);
            }
        }              
    }
}

나는 이것을 할 수 있는 정확하고 유효한 방법을 찾을 수 없었다.그래서 하루 만에 저는 다양한 소스로부터 얻은 이 혼합된 코드를 가지고 와서 작업을 완료하기 위해 노력했습니다.

.ExecuteNonQuery: CommandText property has not been Initialized스크립트 파일이 정상적으로 실행되더라도 제 경우 데이터베이스를 성공적으로 만들고 첫 번째 부팅 시 데이터를 삽입합니다.

public partial class Form1 : MetroForm
{
    SqlConnection cn;
    SqlCommand cm;
    public Form1()
    {
        InitializeComponent();
    }

    private void Form1_Load(object sender, EventArgs e)
    {
        if (!CheckDatabaseExist())
        {
            GenerateDatabase();
        }
    }

    private bool CheckDatabaseExist()
    {
        SqlConnection con = new SqlConnection(@"Data Source=.\SQLEXPRESS;Initial Catalog=SalmanTradersDB;Integrated Security=true");
        try
        {
            con.Open();
            return true;
        }
        catch
        {
            return false;
        }
    }

    private void GenerateDatabase()
    {

        try
        {
            cn = new SqlConnection(@"Data Source=.\SQLEXPRESS;Initial Catalog=master;Integrated Security=True");
            StringBuilder sb = new StringBuilder();
            sb.Append(string.Format("drop databse {0}", "SalmanTradersDB"));
            cm = new SqlCommand(sb.ToString() , cn);
            cn.Open();
            cm.ExecuteNonQuery();
            cn.Close();
        }
        catch
        {

        }
        try
        {
            //Application.StartupPath is the location where the application is Installed
            //Here File Path Can Be Provided Via OpenFileDialog
            if (File.Exists(Application.StartupPath + "\\script.sql"))
            {
                string script = null;
                script = File.ReadAllText(Application.StartupPath + "\\script.sql");
                string[] ScriptSplitter = script.Split(new string[] { "GO" }, StringSplitOptions.None);
                using (cn = new SqlConnection(@"Data Source=.\SQLEXPRESS;Initial Catalog=master;Integrated Security=True"))
                {
                    cn.Open();
                    foreach (string str in ScriptSplitter)
                    {
                        using (cm = cn.CreateCommand())
                        {
                            cm.CommandText = str;
                            cm.ExecuteNonQuery();
                        }
                    }
                }
            }
        }
        catch
        {

        }

    }

}

마이크로소프트를 사용한 닷넷용 새로운 솔루션.SqlServer.DacFx

배치에 의해 반환된 모든 결과에 완전히 액세스할 수 있습니다.

fsharp 인터랙티브용으로 작성되다

사용방법:

dotnet fsi --exec file.fsx connection-string sql-files-files

// https://github.com/dotnet/SqlClient/issues/1397
// https://github.com/dotnet/fsharp/issues/12703
#r "nuget: Microsoft.Data.SqlClient, 3.0"

#r "nuget: Microsoft.SqlServer.DacFx"

open System
open System.IO
open System.Text
open System.Collections.Generic
open Microsoft.Data.SqlClient
open Microsoft.SqlServer.TransactSql.ScriptDom

let tokens (f:TSqlFragment) = seq {
  for i = f.FirstTokenIndex to f.LastTokenIndex do yield f.ScriptTokenStream[i]
}

let fragToString (f:TSqlFragment) =
  let append (b:StringBuilder) (t:TSqlParserToken) = b.Append(t.Text)
  (Seq.fold append (StringBuilder()) (tokens f)).ToString()

let parse file =
  let parser = TSql150Parser(false)
  use textReader = File.OpenText(file) :> TextReader
  let mutable errors : IList<_> = Unchecked.defaultof<IList<_>>
  let res = parser.Parse(textReader, &errors)
  match errors.Count with
  | 0 -> res
  | _ -> failwith $"parse error in file {file}"

let cs = SqlConnectionStringBuilder(fsi.CommandLineArgs[1])
let dbConn = new SqlConnection(cs.ConnectionString)
dbConn.Open()

let visitor = {
  new TSqlFragmentVisitor() with
  override this.Visit(statement:TSqlBatch) =
    let sql = fragToString statement
    printfn $"running batch:\n{sql}"
    let cmd = new SqlCommand(sql, dbConn)
    cmd.ExecuteNonQuery() |> ignore
}
let parsed = parse fsi.CommandLineArgs[2]
parsed.Accept(visitor)

언급URL : https://stackoverflow.com/questions/650098/how-to-execute-an-sql-script-file-using-c-sharp

반응형