Cara menjalankan file skrip .SQL menggunakan c #

140

Saya yakin pertanyaan ini sudah dijawab, namun saya tidak dapat menemukan jawaban menggunakan alat pencarian.

Menggunakan c # Saya ingin menjalankan file .sql. File sql berisi beberapa pernyataan sql, beberapa di antaranya rusak karena beberapa baris. Saya mencoba membaca dalam file dan mencoba mengeksekusi file menggunakan ODP.NET ... namun saya tidak berpikir ExecuteNonQuery benar-benar dirancang untuk melakukan ini.

Jadi saya mencoba menggunakan sqlplus melalui pemijinan sebuah proses ... namun kecuali saya memunculkan proses dengan UseShellExecute yang disetel ke sqlplus sejati akan hang dan tidak pernah keluar. Berikut kode yang TIDAK BEKERJA.

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 tidak pernah kembali .... Kecuali saya mengatur UseShellExecute menjadi true. Efek samping dari UseShellExecute adalah Anda tidak dapat menangkap output yang dialihkan.

Kaya
sumber
8
Halo Tn. Rich, pertanyaan Anda tentang Oracle dan Anda menerima solusi untuk sql server? Anda mengubah DB ke server sql?
Akshay J

Jawaban:

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

sumber
4
Bagus! Solusi ini berhasil bagi saya karena dapat menjatuhkan dan membuat ulang basis data, dan menambahkan tabel (melalui file skrip SQL yang direferensikan).
Ogre Psalm33
11
Metode ini tidak mengizinkan penggunaan perintah "GO" di skrip Anda yang diizinkan saat Anda menjalankan skrip dari SQL Management Studio atau perintah osql. msdn.microsoft.com/en-us/library/ms188037.aspx
Rn222
20
Rn222: Saya pikir Anda sudah bingung metode ExecuteNonQuery, SqlCommand.ExecuteNonQuery tidak akan mengizinkan menggunakan perintah "GO", namun Server.ConnectionContext.ExecuteNonQuery pasti melakukannya (saya menggunakannya sekarang).
PeterBelm
44
Perhatikan bahwa Anda perlu menambahkan referensi ke proyek, ke Microsoft.SqlServer.ConnectionInfo, Microsoft.SqlServer.Management.Sdk dan Microsoft.SqlServer.Smo untuk jawaban ini berfungsi.
thomasb
8
Bagi saya itu tidak berfungsi ketika menggunakan .net 4.0 / 4.5, ketika merujuk 110 \ SDK \ Assemblies Solusi yang saya temukan adalah mengubah app.Config to<startup useLegacyV2RuntimeActivationPolicy="true"> <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5"/> </startup>
Abir
107

Saya mencoba solusi ini dengan Microsoft.SqlServer.Management tetapi tidak bekerja dengan baik dengan .NET 4.0 jadi saya menulis solusi lain menggunakan .NET libs framework saja.

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();
Hacko
sumber
Persis. Solusi ini bahkan tidak akan menutup file setelah selesai menggunakannya. Itu bisa kritis.
Mathias Lykkegaard Lorenzen
1
Gunakan "RegexOptions.Multiline | RegexOptions.IgnoreCase" untuk mencocokkan kasus "Go" atau "go" juga.
Ankush
1
Saya pikir bendera RegexOptions.CultureInvariant harus digunakan juga.
Dave Andersen
3
Ini tidak 100% berfungsi: 'GO' dapat menerima parameter numerik.
nothrow
16

Ini Berfungsi pada Kerangka 4.0 atau Lebih Tinggi. Mendukung "GO". Juga menunjukkan pesan kesalahan, baris, dan perintah 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;
        }
    }
Xtian11
sumber
3
Kode yang bagus, satu hal yang sangat kecil adalah bahwa tidak perlu connection.Close()koneksi akan ditutup oleh usingAnda telah membungkusnya.
Amicable
Kerja bagus. Itu bekerja 'langsung dari kotak' untukku.
Stephen85
8

Masukkan perintah untuk mengeksekusi skrip sql ke dalam file batch kemudian jalankan kode di bawah ini

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 )

dalam file batch menulis sesuatu seperti ini (sampel untuk server sql)

osql -E -i %1
Binoj Antony
sumber
6

Ini bekerja untuk saya:

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();
    }
}
Neelam saini
sumber
4

Menambahkan peningkatan tambahan pada jawaban 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);
            }
        }
    }
}

Juga, saya harus menambahkan referensi berikut ke proyek saya:

  • 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

Saya tidak tahu apakah itu adalah hak dll: s untuk digunakan karena ada beberapa folder di C: \ Program Files \ Microsoft SQL Server tetapi dalam aplikasi saya dua pekerjaan ini.

Kucing dalam sepatu
sumber
Ini bekerja untuk saya di. Net 4.7. Saya tidak perlu dll lain yang disebutkan oleh surajit. Namun, saya harus menggunakan versi 13.0.0.0 untuk Microsoft.SqlServer.ConnectionInfo dan Microsoft.SqlServer.Smo, karena 13.100.0.0 melempar pengecualian ketika membuat instance ServerConnection.
Kevin Fichter
4

Saya berhasil mencari jawabannya dengan membaca manual :)

Ekstrak ini dari MSDN

Contoh kode menghindari kondisi jalan buntu dengan memanggil p.StandardOutput.ReadToEnd sebelum p.WaitForExit. Kondisi jalan buntu dapat terjadi jika proses induk memanggil p.WaitForExit sebelum p.StandardOutput.ReadToEnd dan proses anak menulis teks yang cukup untuk mengisi aliran yang dialihkan. Proses induk akan menunggu tanpa batas waktu untuk proses anak keluar. Proses anak akan menunggu tanpa batas waktu untuk orang tua membaca dari aliran StandardOutput penuh.

Ada masalah yang sama ketika Anda membaca semua teks dari output standar dan stream kesalahan standar. Misalnya, kode C # berikut melakukan operasi baca di kedua aliran.

Ubah kode menjadi ini;

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

Yang sekarang keluar dengan benar.

Kaya
sumber
2
Tip tentang sqlplus: jika Anda ingin tahu apakah eksekusi skrip berhasil, Anda dapat menambahkan WHEREVER SQLERROR EXIT SQL.SQLCODE di awal skrip. Dengan cara ini proses sqlplus mengembalikan nomor kesalahan sql sebagai kode pengembalian.
devdimi
sampel kode sumber lengkap lengkap? Apa itu in_database, s ??
Kiquenet
2
ini tidak bekerja untuk saya. p.StandardOutput.ReadToEnd();tidak pernah keluar
Louis Rhys
2

Ada dua hal yang perlu diperhatikan.

1) Kode sumber ini berfungsi untuk saya:

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

Saya mengatur direktori kerja ke direktori skrip, sehingga sub skrip di dalam skrip juga berfungsi.

Sebut saja misalnya sebagai Execute("usr/pwd@service", "c:\myscripts", "script.sql")

2) Anda harus menyelesaikan skrip SQL Anda dengan pernyataan tersebut EXIT;

StefanG
sumber
1

Menggunakan EntityFramework, Anda bisa menggunakan solusi seperti ini. Saya menggunakan kode ini untuk menginisialisasi tes e2e. Untuk mencegah serangan injeksi sql, pastikan untuk tidak membuat skrip ini berdasarkan input pengguna atau menggunakan parameter perintah untuk ini (lihat kelebihan ExecuteSqlCommand yang menerima parameter).

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);
            }
        }              
    }
}
martinoss
sumber
-1

Saya tidak dapat menemukan cara yang tepat dan valid untuk melakukan ini. Jadi setelah seharian, saya datang dengan kode campuran ini diraih dari berbagai sumber dan mencoba menyelesaikan pekerjaan.

Tetapi masih menghasilkan pengecualian ExecuteNonQuery: CommandText property has not been Initializedmeskipun berhasil menjalankan file skrip - dalam kasus saya, itu berhasil membuat database dan memasukkan data pada startup pertama.

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
        {

        }

    }

}
Muhammad Salman
sumber
Saya tidak dapat menemukan cara yang tepat dan valid untuk melakukan ini. Jadi setelah seharian, saya datang dengan kode campuran ini diraih dari berbagai sumber dan mencoba menyelesaikan pekerjaan. jadi saya menggabungkan semuanya dan membuat hasilnya. Tetapi masih menghasilkan pengecualian "ExecuteNonQuery: properti CommandText belum diinisialisasi." Meskipun Berhasil menjalankan file skrip (Dalam kasus saya, berhasil membuat database dan memasukkan data pada startup pertama).
Muhammad Salman