[c#] 대규모 SQL 스크립트 실행 (GO 명령 사용)

C # 프로그램 내에서 대량의 SQL 문 (테이블, 뷰 및 저장 프로 시저 생성)을 실행해야합니다.

이러한 문은 문으로 구분해야 GO하지만 문을 SqlCommand.ExecuteNonQuery()좋아하지 않습니다 GO. 참조 용으로 게시 할 것이라고 생각하는 내 솔루션은 SQL 문자열을 GO줄로 분할하고 각 배치를 개별적으로 실행 하는 것이 었습니다 .

더 쉽고 더 나은 방법이 있습니까?



답변

GO 구분 기호를 이해하는 SQL Server 관리 개체 (SMO)를 사용합니다. 여기 내 블로그 게시물을 참조하십시오 : http://weblogs.asp.net/jongalloway/Handling-_2200_GO_2200_-Separators-in-SQL-Scripts- 2D00 -the-easy-way

샘플 코드 :

public static void Main()
{
  string scriptDirectory = "c:\\temp\\sqltest\\";
  string sqlConnectionString = "Integrated Security=SSPI;" +
  "Persist Security Info=True;Initial Catalog=Northwind;Data Source=(local)";
  DirectoryInfo di = new DirectoryInfo(scriptDirectory);
  FileInfo[] rgFiles = di.GetFiles("*.sql");
  foreach (FileInfo fi in rgFiles)
  {
        FileInfo fileInfo = new FileInfo(fi.FullName);
        string script = fileInfo.OpenText().ReadToEnd();
        using (SqlConnection connection = new SqlConnection(sqlConnectionString))
        {
            Server server = new Server(new ServerConnection(connection));
            server.ConnectionContext.ExecuteNonQuery(script);
        }
   }
}

이것이 작동하지 않으면 Phil Haack의 라이브러리를 참조하십시오. http://haacked.com/archive/2007/11/04/a-library-for-executing-sql-scripts-with-go-separators -and.aspx


답변

이것이 바로 내 당면한 문제를 해결하기 위해 함께 두드린 것입니다.

private void ExecuteBatchNonQuery(string sql, SqlConnection conn) {
    string sqlBatch = string.Empty;
    SqlCommand cmd = new SqlCommand(string.Empty, conn);
    conn.Open();
    sql += "\nGO";   // make sure last batch is executed.
    try {
        foreach (string line in sql.Split(new string[2] { "\n", "\r" }, StringSplitOptions.RemoveEmptyEntries)) {
            if (line.ToUpperInvariant().Trim() == "GO") {
                cmd.CommandText = sqlBatch;
                cmd.ExecuteNonQuery();
                sqlBatch = string.Empty;
            } else {
                sqlBatch += line + "\n";
            }
        }
    } finally {
        conn.Close();
    }
}

GO 명령이 자체 라인에 있어야하며 블록 주석을 감지하지 않으므로 이런 종류의 것이 분할되어 오류가 발생합니다.

ExecuteBatchNonQuery(@"
    /*
    GO
    */", conn);


답변

SQL 관리 개체 를 사용하여이를 수행 할 수 있습니다 . 이는 Management Studio가 쿼리를 실행하는 데 사용하는 것과 동일한 개체입니다. 나는 Server.ConnectionContext.ExecuteNonQuery()당신이 필요한 것을 수행 할 것이라고 믿습니다 .


답변

“GO”일괄 구분 키워드는 실제로 SQL Management Studio 자체에서 사용되므로 서버로 보내는 일괄 처리를 종료 할 위치를 알고 SQL 서버로 전달되지 않습니다. 원하는 경우 Management Studio에서 키워드를 변경할 수도 있습니다.


답변

나는로 결정 끝에 몇 번 이것 좀 봐 EF 구현
A를 위해 수정 비트SqlConnection

public static void ExecuteSqlScript(this SqlConnection sqlConnection, string sqlBatch)
        {
            // Handle backslash utility statement (see http://technet.microsoft.com/en-us/library/dd207007.aspx)
            sqlBatch = Regex.Replace(sqlBatch, @"\\(\r\n|\r|\n)", string.Empty);

            // Handle batch splitting utility statement (see http://technet.microsoft.com/en-us/library/ms188037.aspx)
            var batches = Regex.Split(
                sqlBatch,
                string.Format(CultureInfo.InvariantCulture, @"^\s*({0}[ \t]+[0-9]+|{0})(?:\s+|$)", BatchTerminator),
                RegexOptions.IgnoreCase | RegexOptions.Multiline);

            for (int i = 0; i < batches.Length; ++i)
            {
                // Skip batches that merely contain the batch terminator
                if (batches[i].StartsWith(BatchTerminator, StringComparison.OrdinalIgnoreCase) ||
                    (i == batches.Length - 1 && string.IsNullOrWhiteSpace(batches[i])))
                {
                    continue;
                }

                // Include batch terminator if the next element is a batch terminator
                if (batches.Length > i + 1 &&
                    batches[i + 1].StartsWith(BatchTerminator, StringComparison.OrdinalIgnoreCase))
                {
                    int repeatCount = 1;

                    // Handle count parameter on the batch splitting utility statement
                    if (!string.Equals(batches[i + 1], BatchTerminator, StringComparison.OrdinalIgnoreCase))
                    {
                        repeatCount = int.Parse(Regex.Match(batches[i + 1], @"([0-9]+)").Value, CultureInfo.InvariantCulture);
                    }

                    for (int j = 0; j < repeatCount; ++j)
                    {
                       var command = sqlConnection.CreateCommand();
                       command.CommandText = batches[i];
                       command.ExecuteNonQuery();
                    }
                }
                else
                {
                    var command = sqlConnection.CreateCommand();
                    command.CommandText = batches[i];
                    command.ExecuteNonQuery();
                }
            }
        }


답변

SMO 개체를 설치하지 않으려면 gplex 도구를 사용할 수 있습니다 ( 이 답변 참조 )


답변

Blorgbeard의 솔루션을 기반으로합니다.

foreach (var sqlBatch in commandText.Split(new[] { "GO" }, StringSplitOptions.RemoveEmptyEntries))
{
   sqlCommand.CommandText = sqlBatch;
   sqlCommand.ExecuteNonQuery();
}