我看到了这个教程,以了解如何使用GO语句执行SQL脚本。
现在我想知道如何获取消息TAB的输出。
对于多个GO语句,输出将会是这样的:
1 行受影响
912 行受影响
...
但是server.ConnectionContext.ExecuteNonQuery()只能返回一个整数,而我需要所有的文本。如果查询中有错误,它也应该将其放入输出中。 非常感谢任何帮助。
ExecuteNonQuery
返回的数字:int rowsAffected = server.ConnectionContext.ExecuteNonQuery(/* ... */);
if (rowsAffected != -1)
{
Console.WriteLine("{0} rows affected.", rowsAffected);
}
SET NOCOUNT
设置。ServerConnection.ExecuteNonQuery()
方法,而是通过访问基础SqlConnection
对象创建一个SqlCommand
对象。在其中订阅StatementCompleted
事件。using (SqlCommand command = server.ConnectionContext.SqlConnectionObject.CreateCommand())
{
// Set other properties for "command", like StatementText, etc.
command.StatementCompleted += (s, e) => {
Console.WriteLine("{0} row(s) affected.", e.RecordCount);
};
command.ExecuteNonQuery();
}
GO
分隔符处拆分输入脚本/语句,因为您回到了使用 SqlCommand.Execute*()
,它无法同时处理多个批次。有多种选择:
GO
开头的行(注意:GO
可以像 GO 5
一样调用,例如执行前一个批次 5 次)。我选择后者,这需要相当多的工作,因为它没有很好的文档和示例(稍微谷歌一下,你会找到一些东西,或者使用反射器查看 SMO-Assemblies 如何使用该类)。
使用ManagedBatchParser
的好处(也许是负担)是,它还会为您解析T-SQL脚本的所有其他结构(用于SQLCMD.EXE
)。包括::setvar
、:connect
、:quit
等。当然,如果您的脚本不使用它们,您就不必实现相应的ICommandExecutor
成员。但请注意,您可能无法执行“任意”脚本。IBatchSource
的好文档或示例,这是我采用的方法。internal abstract class BatchSource : IBatchSource
{
private string m_content;
public void Populate()
{
m_content = GetContent();
}
public void Reset()
{
m_content = null;
}
protected abstract string GetContent();
public ParserAction GetMoreData(ref string str)
{
str = null;
if (m_content != null)
{
str = m_content;
m_content = null;
}
return ParserAction.Continue;
}
}
internal class FileBatchSource : BatchSource
{
private readonly string m_fileName;
public FileBatchSource(string fileName)
{
m_fileName = fileName;
}
protected override string GetContent()
{
return File.ReadAllText(m_fileName);
}
}
internal class StatementBatchSource : BatchSource
{
private readonly string m_statement;
public StatementBatchSource(string statement)
{
m_statement = statement;
}
protected override string GetContent()
{
return m_statement;
}
}
这是如何使用它的:
var source = new StatementBatchSource("SELECT GETUTCDATE()");
source.Populate();
var parser = new Parser();
parser.SetBatchSource(source);
/* other parser.Set*() calls */
parser.Parse();
StatementBatchSource
)还是文件(FileBatchSource
)的两种实现方式都存在一个问题,即它们会一次性将完整的文本读入内存。我曾遇到过这样的情况,有一个巨大的脚本包含了海量生成的INSERT
语句,导致内存崩溃。虽然我不认为这是一个实际问题,但SQLCMD.EXE
可以处理。但我却一直搞不清楚应该如何形成返回给IBatchParser.GetContent()
的块,以便解析器仍然可以使用它们(看起来它们需要是完整的语句,这在第一次解析时可能会失去意义...)。
SQLCMD.EXE
进行测试。后者特别是针对ICommandExecutor
的Ed
、ListVar
、ServerList
等方法以及IVariableResolver
方法(类似于SQLCMD.EXE
中的:setvar
等)。关于IBatchSource
的实现,我会更新我的答案。 - Christian.K