【发布时间】:2012-05-25 15:42:21
【问题描述】:
我有一个很大的 SQL 文本文件,其中有很多用于创建表、列等的 SQL 命令。
示例行:
IF NOT EXISTS ( SELECT * FROM dbo.sysobjects WHERE id = object_id(N'xcal_views') AND OBJECTPROPERTY(id, N'IsUserTable') = 1)
CREATE TABLE xcal_views (lid INT NOT NULL);
GO
IF NOT EXISTS ( SELECT * FROM dbo.sysobjects WHERE id = object_id(N'xcal_views_actors') AND OBJECTPROPERTY(id, N'IsUserTable') = 1)
CREATE TABLE xcal_views_actors (lid INT NOT NULL);
GO
IF NOT EXISTS ( SELECT * FROM dbo.syscolumns, dbo.sysobjects WHERE [dbo].[syscolumns].[name] = 'xlactor' AND [dbo].[sysobjects].[id] = [dbo].[syscolumns].[id] AND [dbo].[sysobjects].[id] = object_id(N'xcal_views_actors') AND OBJECTPROPERTY([dbo].[sysobjects].[id], N'IsUserTable') = 1 )
ALTER TABLE [dbo].[xcal_views_actors] ADD xlactor INT NULL;
GO
IF NOT EXISTS ( SELECT * FROM dbo.syscolumns, dbo.sysobjects WHERE [dbo].[syscolumns].[name] = 'lparentid' AND [dbo].[sysobjects].[id] = [dbo].[syscolumns].[id] AND [dbo].[sysobjects].[id] = object_id(N'xcal_views_actors') AND OBJECTPROPERTY([dbo].[sysobjects].[id], N'IsUserTable') = 1 )
ALTER TABLE [dbo].[xcal_views_actors] ADD lparentid INT NULL;
GO
IF NOT EXISTS ( SELECT * FROM dbo.sysobjects WHERE parent_obj = (SELECT id FROM dbo.sysobjects WHERE id = object_id(N'xcal_views_actors') AND OBJECTPROPERTY(id, N'IsUserTable') = 1) AND OBJECTPROPERTY(id, N'IsPrimaryKey') = 1)
ALTER TABLE [dbo].[xcal_views_actors]
ADD CONSTRAINT [CT_00000501] PRIMARY KEY CLUSTERED (lid ASC);
GO
IF NOT EXISTS ( SELECT * FROM [sys].[indexes] i INNER JOIN [sys].[objects] o ON o.object_id = i.object_id AND o.name = 'xcal_views_actors' WHERE i.name = 'parent_id' )
CREATE INDEX parent_id ON xcal_views_actors (lparentid ASC)
GO
在每个命令之间,我在额外的行中有一个 GO 来分隔命令。
如果我从 SQL Server Management Studio 运行整个 patch.sql 文件,所有命令都会执行并且工作正常。
在 .NET 中,我读取了整个文本文件,然后用 'GO' 拆分它们并对数据库执行每个 SQL 命令。
现在奇怪的是:有些命令没有被执行。我不知道为什么。
这是完成这项工作的方法:
private static void patchDatabase(string connection, string sqlfile)
{
var defaultEncoding = Encoding.Default;
using (FileStream fs = File.OpenRead(sqlfile))
{
defaultEncoding = TextFileEncodingDetector.DetectTextFileEncoding(fs, defaultEncoding, 1024);
}
//Console.WriteLine(string.Format("File {0} using encoding: {1}",sqlfile, defaultEncoding));
var dbPatch = new StreamReader(sqlfile, defaultEncoding);
string sqlPatch = dbPatch.ReadToEnd();
dbPatch.Close();
string[] stringSeparators = new[] {"GO"};
string[] sqlPatches = sqlPatch.Split(stringSeparators, StringSplitOptions.None);
if (connection != null && sqlPatch.Length > 0)
{
Console.WriteLine(string.Format("Executing {0} statements from {1}", sqlPatches.Length, sqlfile));
using (var cnn = new SqlConnection(connection))
{
cnn.Open();
foreach (var sql in sqlPatches)
{
if (String.IsNullOrEmpty(sql))
continue; // Not a real sql statement, use next
using (var cmd = new SqlCommand(sql, cnn))
{
try
{
cmd.CommandTimeout = 120;
cmd.ExecuteNonQuery();
//int results = cmd.ExecuteNonQuery();
//if (results < 1)
// Console.WriteLine(String.Format("Failed:\nResult: {0}\n{1}",results, sql));
}
catch (Exception ex)
{
Console.WriteLine("Execution error!\n\n" + sql + "\n\n\n" + ex);
}
}
}
cnn.Close();
}
}
}
看起来我的函数崩溃了……
我当前的文本文件大约有 6000 多行。
知道我做错了什么吗?
【问题讨论】:
-
很好奇为什么你有这么大的脚本文件,它可以作为单个脚本运行,并且觉得需要通过 GO 拆分它并独立调用每个批处理?为什么不一次性运行整个脚本呢?另外,我不确定我是否理解您为什么无法弄清楚发生了什么……您的 Control.WriteLine 输出在哪里?你怎么知道有些命令没有运行?
-
如果没有单个语句需要成为批处理中的第一个,您可以将 NewLine+GO+NewLine 替换为 newline 并运行脚本;否则你最好看看this SO answer。
-
@AaronBertrand 我拆分它是因为我想执行每个语句并在失败时得到结果。此外,如果一个语句失败,我想确保所有其他语句继续。该方法是从 cmd.exe 行工具调用的,因此我得到结果或将其重定向到文本文件。另一个原因是超时。我的一些陈述也是更复杂的东西(比如需要更多时间的程序)。从管理工作室调用它只是为了测试,通常所有语句都是从我的命令工具调用的。
-
如果您的存储过程需要超过 2 分钟才能编译,我会说这是一个完全不同的问题。无论如何,正如我建议的那样,您的脚本目前似乎将异常结果输出到 Console.WriteLine。您是否查看了此输出以了解问题出在哪里?
-
@NikolaMarkovinović 您的链接答案与我所看到的方法相同。
标签: sql-server c#-4.0 patch