C # का उपयोग करके .SQL स्क्रिप्ट फ़ाइल को कैसे निष्पादित करें


140

मुझे यकीन है कि इस प्रश्न का उत्तर पहले ही दिया जा चुका है, हालांकि मैं खोज टूल का उपयोग करके उत्तर खोजने में असमर्थ था।

C # का उपयोग करके मैं .sql फ़ाइल चलाना चाहता हूँ। Sql फ़ाइल में कई sql कथन होते हैं, जिनमें से कुछ कई लाइनों पर टूट जाते हैं। मैंने फ़ाइल में पढ़ने की कोशिश की और ODP.NET का उपयोग करके फ़ाइल को निष्पादित करने की कोशिश की ... हालांकि मुझे नहीं लगता कि ExecuteNonQuery वास्तव में ऐसा करने के लिए डिज़ाइन किया गया है।

इसलिए मैंने एक प्रक्रिया को स्पैनिंग के माध्यम से 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 को सही पर सेट नहीं करता। UseShellExecute का एक साइड इफेक्ट यह है कि आप रीडायरेक्ट आउटपुट को कैप्चर नहीं कर सकते हैं।


8
हेलो मिस्टर रिच, आपका सवाल ओरेकल के बारे में था और आपने एक समाधान स्वीकार किया था जो एसक्यूएल सर्वर के लिए था? आपने अपने DB को sql सर्वर में बदल दिया है?
अक्षय J

जवाबों:


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

4
महान! इस समाधान ने एक डेटाबेस को छोड़ने और पुन: बनाने में सक्षम होने और तालिकाओं (संदर्भित SQL स्क्रिप्ट फ़ाइल के माध्यम से) को जोड़ने के लिए मेरे लिए काम किया।
Ogre Psalm33

11
यह विधि आपकी स्क्रिप्ट में "गो" कमांड का उपयोग करने की अनुमति नहीं देती है, जब आपको SQL प्रबंधन स्टूडियो या ऑस्कल कमांड से स्क्रिप्ट चलाने की अनुमति होती है। msdn.microsoft.com/en-us/library/ms188037.aspx
Rn222

20
Rn222: मुझे लगता है कि आपने ExecuteNonQuery के तरीकों को भ्रमित किया है, SqlCommand.ExecuteNonQuery "GO" कमांड का उपयोग करने की अनुमति नहीं देगा, हालांकि Server.ConnectionContext.ExecuteNonQuery निश्चित रूप से करता है (मैं अभी इसका उपयोग कर रहा हूं)।
पीटरबेलम

44
ध्यान दें कि आपको इस उत्तर के लिए प्रोजेक्ट के संदर्भों को Microsoft.SqlServer.ConnectionInfo, Microsoft.SqlServer.Management.Sdk और Microsoft.SqlServer.Smo में जोड़ने की आवश्यकता है।
थोमसब

8
मेरे लिए यह तब काम नहीं आया जब .net 4.0 / 4.5 का उपयोग करते समय, जब 110 \ SDK \ Assemblies का संदर्भ दिया जाता है, तो मुझे जो समाधान मिला वह एप्लिकेशन को बदल रहा था। कॉनफिग टू<startup useLegacyV2RuntimeActivationPolicy="true"> <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5"/> </startup>
अबीर

107

मैंने Microsoft.SqlServer.Management के साथ इस समाधान की कोशिश की, लेकिन यह .NET 4.0 के साथ अच्छी तरह से काम नहीं करता था, इसलिए मैंने केवल .NET लिबास फ्रेमवर्क का उपयोग करके एक और समाधान लिखा।

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

बिल्कुल सही। इसका उपयोग करने के बाद यह समाधान फ़ाइल को बंद नहीं करेगा। यह महत्वपूर्ण हो सकता है।
मैथियास लिकेगार्ड लोरेंजेन

1
"गो" या "गो" मामलों से भी मिलान करने के लिए "RegexOptions.Multiline | RegexOptions.IgnoreCase" का उपयोग करें।
अंकुश

1
मुझे लगता है कि RegexOptions.CultureInvariant ध्वज का उपयोग किया जाना चाहिए।
डेव एंडरसन

3
यह 100% काम नहीं कर रहा है: 'GO' संख्यात्मक पैरामीटर को स्वीकार कर सकता है।
नॉट्रो

16

यह फ्रेमवर्क 4.0 या उच्चतर पर काम करता है। "गो" का समर्थन करता है। त्रुटि संदेश, लाइन और 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;
        }
    }

3
अच्छा कोड, एक बहुत ही मामूली बात यह है कि आपके द्वारा इसे लपेटे connection.Close()जाने से कनेक्शन बंद होने की आवश्यकता नहीं usingहै।
Amicable

अच्छा कार्य। इसने मेरे लिए 'स्ट्रेट आउट्टा द बॉक्स' काम किया।
स्टीफन 85

8

एक बैच फ़ाइल में एसक्यूएल स्क्रिप्ट निष्पादित करने के लिए कमांड रखो फिर नीचे दिए गए कोड को चलाएं

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

6

यह मेरे लिए काम करता है:

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

4

अतिरिक्त सुधार सुराजित उत्तर में जोड़े:

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 में कई फ़ोल्डर हैं, लेकिन मेरे आवेदन में ये दोनों काम करते हैं।


यह मेरे लिए .Net 4.7 में काम करता है। मुझे सुराजित द्वारा उल्लिखित अन्य dll की आवश्यकता नहीं थी। हालाँकि, मुझे Microsoft.SqlServer.ConnectionInfo और Microsoft.SqlServer.Smo दोनों के लिए संस्करण 13.0.0.0 का उपयोग करना पड़ा, क्योंकि 13.100.0.0 सर्वर अपवाद को तत्काल करते समय अपवादों को फेंक दिया।
केविन फिचर

4

मैं मैनुअल पढ़कर जवाब देने में कामयाब रहा :)

यह MSDN से निकालता है

कोड उदाहरण p.WtitFitExit से पहले p.StandardOutput.ReadToEnd पर कॉल करके एक डेडलॉक स्थिति से बचा जाता है। यदि कोई पैरेंट प्रक्रिया p.WtForExit से पहले p.StandardOutput.ReadToEnd से पहले कॉल करती है तो डेडलॉक की स्थिति उत्पन्न हो सकती है और बच्चे की प्रक्रिया पुनर्निर्देशित स्ट्रीम को भरने के लिए पर्याप्त पाठ लिखती है। मूल प्रक्रिया बच्चे की प्रक्रिया से बाहर निकलने के लिए अनिश्चित काल तक प्रतीक्षा करेगी। बच्चे की प्रक्रिया पूरी तरह से मानक Standardutut स्ट्रीम से पढ़ने के लिए माता-पिता की अनिश्चित प्रतीक्षा करेगी।

एक समान समस्या है जब आप मानक आउटपुट और मानक त्रुटि धाराओं दोनों से सभी पाठ पढ़ते हैं। उदाहरण के लिए, निम्न 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;
}

जो अब सही तरीके से बाहर निकलता है।


2
Sqlplus के बारे में एक टिप: यदि आप जानना चाहते हैं कि क्या स्क्रिप्ट निष्पादन सफल था, तो आप स्क्रिप्ट की शुरुआत में WHENEVER SQLERROR EXIT SQL.SQLCODE जोड़ सकते हैं। इस तरह sqlplus प्रक्रिया sql त्रुटि संख्या को रिटर्न कोड के रूप में लौटाती है।
देवदिमी

कोई भी पूर्ण स्रोत कोड नमूना? क्या है in_database, s ??
किनिकेत

2
यह मेरे लिए काम नहीं करता है। p.StandardOutput.ReadToEnd();कभी बाहर नहीं निकलता
लुईस

2

विचार करने के लिए दो बिंदु हैं।

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;


1

EntityFramework का उपयोग करके, आप इस तरह के समाधान के साथ जा सकते हैं। मैं इस कोड का उपयोग e2e परीक्षणों को शुरू करने के लिए करता हूं। डी एसक्यूएल इंजेक्शन के हमलों को रोकें, सुनिश्चित करें कि यह स्क्रिप्ट उपयोगकर्ता इनपुट के आधार पर उत्पन्न नहीं होती है या इसके लिए कमांड मापदंडों का उपयोग नहीं करती है (देखें एक्सेल्यूटसक्लेमकम का अधिभार जो मापदंडों को स्वीकार करता है)।

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

-1

मुझे ऐसा करने का कोई सटीक और मान्य तरीका नहीं मिला। इसलिए एक पूरे दिन के बाद, मैं इस मिश्रित कोड को विभिन्न स्रोतों से हासिल किया और काम पाने की कोशिश कर रहा था।

लेकिन यह अभी भी एक अपवाद उत्पन्न कर रहा है, 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
        {

        }

    }

}

मुझे ऐसा करने का कोई सटीक और मान्य तरीका नहीं मिला। इसलिए एक पूरे दिन के बाद, मैं विभिन्न स्रोतों से प्राप्त इस मिश्रित कोड के साथ आया और काम पाने की कोशिश कर रहा था। इसलिए मैंने उन सभी को मिला दिया और परिणाम बना। लेकिन यह अभी भी एक अपवाद उत्पन्न कर रहा है "ExecuteNonQuery: CommandText संपत्ति प्रारंभिक नहीं है।" हालाँकि यह स्क्रिप्ट फ़ाइल को सफलतापूर्वक चलाता है (मेरे मामले में, सफलतापूर्वक डेटाबेस बनाएँ और पहले स्टार्टअप पर डेटा डालें)।
मुहम्मद सलमान
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.