执行批量sql语句

时间:2022-06-28 01:03:58
我的目的是这样:
各个开发的同事都写了sql脚本,每个人写的脚本各式各样, 统一放在一个.sql文件里面
然后一次性执行, 如果有一个地方出错,则全部脚本回滚

因为我们做的这个是持续集成的自动化发布,全程不能人工干预。
所以需要执行脚本异常则全部回滚。

请问有什么方法吗?
谢谢

5 个解决方案

#1


不知道大家的语句有没有 ddl操作。如果有就不能回滚。

这种升级的操作,一定要严格测试,还要有人值守比较好。

#2


我的目的是这样:
各个开发的同事都写了sql脚本,每个人写的脚本各式各样,统一放在一个.sql文件里面。
然后一次性执行,如果有一个地方出错,则全部脚本回滚。
-----------------------------------------------------------------------------------------------------------------
不现实,我们是做到某地方出错,后续批量脚本(出错位置后面go以后的脚本也会终止),但想回滚,不是不可能,难度太大,例如,修改了某个存储过程,基本上就是灾难性的,回退很难,至于前面版主说的“这种升级的操作,一定要严格测试,还要有人值守比较好。”,我不认同,一个客户还好,有十几个客户你就知道这是不可能的,我们的HIS就是基于互联网自动升级,包括数据库都是自动升级,不敢说没出过问题,但都控制在一个可以掌控的范围内

#3


把所有脚本内容,都放到一个脚本中,并在一个事务中执行。

#4


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.SqlClient;
using System.Data;

namespace ConsoleApplication8
{
    class Program
    {
        static void Main(string[] args)
        {
            string connString = @"Data Source=(local)\sqlserver2014;Initial Catalog=tempdb;Integrated Security=True";
            //正确SQL
            string sql_1 =
@"IF OBJECT_ID('t') IS NOT NULL DROP TABLE t
CREATE TABLE t(id INT IDENTITY(1,1) PRIMARY KEY)
GO
ALTER TABLE t ADD c1 INT
go
INSERT INTO t(c1) VALUES(1)
";
            //有错误的SQL
            string sql_2 =
@"INSERT INTO t(c1) VALUES(2)
GO
if object_id('proc_test') is not null drop proc proc_test
go
CREATE PROC Proc_TEST
AS
Begin
    set nocount on
    select 1
end
go
123 -- 注:此处有误
";
            string errMsg = string.Empty;
            bool r1 = ExecuteNonQueryWithConnAndGO(connString, sql_1, ref errMsg);
            Console.WriteLine("SQL1 结果:{0}, 错误信息:{1}", r1 ? "成功":"失败", string.IsNullOrEmpty(errMsg)?"无":errMsg);

            errMsg = string.Empty;
            bool r2 = ExecuteNonQueryWithConnAndGO(connString, sql_2, ref errMsg);
            Console.WriteLine("SQL2 结果:{0}, 错误信息:{1}", r2 ? "成功" : "失败", string.IsNullOrEmpty(errMsg) ? "无" : errMsg);

            //注:第2个SQL有问题,所以第2个SQL全部回滚了,只有第一个SQL的记录
            Print(connString, "select * from t");

            Console.Read();
        }

        #region [ 执行带Go语句 ]
        /// <summary>  
        /// 执行带"GO"的SQL,返回最后一条SQL的受影响行数  
        /// </summary>  
        /// <param name="connString">连接串</param>  
        /// <param name="sql">sql语句</param>  
        /// <returns>是否成功</returns>
        public static bool ExecuteNonQueryWithConnAndGO(string connString, string sql, ref string errMsg)
        {
            bool result = true;
            string[] arr = System.Text.RegularExpressions.Regex.Split(sql, @"\bGO\b", System.Text.RegularExpressions.RegexOptions.IgnoreCase);
            using (SqlConnection conn = new SqlConnection(connString))
            {
                conn.Open();
                SqlCommand cmd = new SqlCommand();
                cmd.Connection = conn;
                SqlTransaction tx = conn.BeginTransaction();
                cmd.Transaction = tx;
                try
                {
                    for (int n = 0; n < arr.Length; n++)
                    {
                        string strsql = arr[n];
                        if (strsql.Trim().Length > 1 && strsql.Trim().Replace(";", "") != "")
                        {
                            cmd.CommandText = strsql;
                            cmd.ExecuteNonQuery();
                        }
                    }
                    tx.Commit();
                }
                catch (System.Data.SqlClient.SqlException ex)
                {
                    tx.Rollback();
                    result = false;
                    errMsg = ex.Message;
                }
            }
            return result;
        }
        #endregion

        public static void Print(string connString, string sql) 
        {
            Console.WriteLine("\r\n------- 输出信息: {0} --------", sql);

            DataTable dt = new DataTable();
            using (SqlConnection conn = new SqlConnection(connString)) 
            {
                conn.Open();
                SqlCommand cmd = new SqlCommand(sql, conn);
                SqlDataAdapter adapter = new SqlDataAdapter(cmd);
                adapter.Fill(dt);
            }

            foreach (DataRow dr in dt.Rows) 
            {
                foreach (DataColumn dc in dt.Columns) 
                {
                    Console.Write("{0}: {1}\t",dc.ColumnName,dr[dc.ColumnName].ToString());
                }
                Console.WriteLine();
            }
        }
    }
}


执行批量sql语句

仿照这个做就是了。

#5


我看到的很多客户是不管HIS,还是ERP升级的话,还是都是出错了就抛出错误,解决错误了,就可以整个全部重新执行。在每个脚本里面要做好判断,保证语句都是可以重新执行的。

#1


不知道大家的语句有没有 ddl操作。如果有就不能回滚。

这种升级的操作,一定要严格测试,还要有人值守比较好。

#2


我的目的是这样:
各个开发的同事都写了sql脚本,每个人写的脚本各式各样,统一放在一个.sql文件里面。
然后一次性执行,如果有一个地方出错,则全部脚本回滚。
-----------------------------------------------------------------------------------------------------------------
不现实,我们是做到某地方出错,后续批量脚本(出错位置后面go以后的脚本也会终止),但想回滚,不是不可能,难度太大,例如,修改了某个存储过程,基本上就是灾难性的,回退很难,至于前面版主说的“这种升级的操作,一定要严格测试,还要有人值守比较好。”,我不认同,一个客户还好,有十几个客户你就知道这是不可能的,我们的HIS就是基于互联网自动升级,包括数据库都是自动升级,不敢说没出过问题,但都控制在一个可以掌控的范围内

#3


把所有脚本内容,都放到一个脚本中,并在一个事务中执行。

#4


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.SqlClient;
using System.Data;

namespace ConsoleApplication8
{
    class Program
    {
        static void Main(string[] args)
        {
            string connString = @"Data Source=(local)\sqlserver2014;Initial Catalog=tempdb;Integrated Security=True";
            //正确SQL
            string sql_1 =
@"IF OBJECT_ID('t') IS NOT NULL DROP TABLE t
CREATE TABLE t(id INT IDENTITY(1,1) PRIMARY KEY)
GO
ALTER TABLE t ADD c1 INT
go
INSERT INTO t(c1) VALUES(1)
";
            //有错误的SQL
            string sql_2 =
@"INSERT INTO t(c1) VALUES(2)
GO
if object_id('proc_test') is not null drop proc proc_test
go
CREATE PROC Proc_TEST
AS
Begin
    set nocount on
    select 1
end
go
123 -- 注:此处有误
";
            string errMsg = string.Empty;
            bool r1 = ExecuteNonQueryWithConnAndGO(connString, sql_1, ref errMsg);
            Console.WriteLine("SQL1 结果:{0}, 错误信息:{1}", r1 ? "成功":"失败", string.IsNullOrEmpty(errMsg)?"无":errMsg);

            errMsg = string.Empty;
            bool r2 = ExecuteNonQueryWithConnAndGO(connString, sql_2, ref errMsg);
            Console.WriteLine("SQL2 结果:{0}, 错误信息:{1}", r2 ? "成功" : "失败", string.IsNullOrEmpty(errMsg) ? "无" : errMsg);

            //注:第2个SQL有问题,所以第2个SQL全部回滚了,只有第一个SQL的记录
            Print(connString, "select * from t");

            Console.Read();
        }

        #region [ 执行带Go语句 ]
        /// <summary>  
        /// 执行带"GO"的SQL,返回最后一条SQL的受影响行数  
        /// </summary>  
        /// <param name="connString">连接串</param>  
        /// <param name="sql">sql语句</param>  
        /// <returns>是否成功</returns>
        public static bool ExecuteNonQueryWithConnAndGO(string connString, string sql, ref string errMsg)
        {
            bool result = true;
            string[] arr = System.Text.RegularExpressions.Regex.Split(sql, @"\bGO\b", System.Text.RegularExpressions.RegexOptions.IgnoreCase);
            using (SqlConnection conn = new SqlConnection(connString))
            {
                conn.Open();
                SqlCommand cmd = new SqlCommand();
                cmd.Connection = conn;
                SqlTransaction tx = conn.BeginTransaction();
                cmd.Transaction = tx;
                try
                {
                    for (int n = 0; n < arr.Length; n++)
                    {
                        string strsql = arr[n];
                        if (strsql.Trim().Length > 1 && strsql.Trim().Replace(";", "") != "")
                        {
                            cmd.CommandText = strsql;
                            cmd.ExecuteNonQuery();
                        }
                    }
                    tx.Commit();
                }
                catch (System.Data.SqlClient.SqlException ex)
                {
                    tx.Rollback();
                    result = false;
                    errMsg = ex.Message;
                }
            }
            return result;
        }
        #endregion

        public static void Print(string connString, string sql) 
        {
            Console.WriteLine("\r\n------- 输出信息: {0} --------", sql);

            DataTable dt = new DataTable();
            using (SqlConnection conn = new SqlConnection(connString)) 
            {
                conn.Open();
                SqlCommand cmd = new SqlCommand(sql, conn);
                SqlDataAdapter adapter = new SqlDataAdapter(cmd);
                adapter.Fill(dt);
            }

            foreach (DataRow dr in dt.Rows) 
            {
                foreach (DataColumn dc in dt.Columns) 
                {
                    Console.Write("{0}: {1}\t",dc.ColumnName,dr[dc.ColumnName].ToString());
                }
                Console.WriteLine();
            }
        }
    }
}


执行批量sql语句

仿照这个做就是了。

#5


我看到的很多客户是不管HIS,还是ERP升级的话,还是都是出错了就抛出错误,解决错误了,就可以整个全部重新执行。在每个脚本里面要做好判断,保证语句都是可以重新执行的。