gpt4 book ai didi

c# - SSMS SMO 对象 : Get query results

转载 作者:太空狗 更新时间:2023-10-30 01:23:05 25 4
gpt4 key购买 nike

我遇到了this了解如何使用 GO 语句执行 SQL 脚本的教程。
现在我想知道我可以得到消息 TAB 的输出。

使用几个 GO 语句,输出将如下所示:
1 行受影响
912 行受影响
...

但是 server.ConnectionContext.ExecuteNonQuery() 只能返回一个 int,而我需要所有文本。如果查询的某些部分出现错误,它也应该将其放在输出中。
任何帮助,将不胜感激。

最佳答案

最简单的方法可能是打印您返回的 ExecuteNonQuery 的号码。 :

int rowsAffected = server.ConnectionContext.ExecuteNonQuery(/* ... */);
if (rowsAffected != -1)
{
Console.WriteLine("{0} rows affected.", rowsAffected);
}

这应该可以,但不会尊重 SET NOCOUNT当前 session /范围的设置。

否则,您将像使用“普通”ADO.NET 一样进行操作。不要使用 ServerConnection.ExecuteNonQuery()方法,但创建一个 SqlCommand对象通过访问底层 SqlConnection目的。在那订阅 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();
}

使用 StatementCompleted (相反,手动打印 ExecuteNonQuery() 返回的值)的好处是它的工作方式与 SSMS 或 SQLCMD.EXE 完全一样:
  • 对于没有 ROWCOUNT 的命令,它根本不会被调用(例如 GO、USE)。
  • 如果 SET NOCOUNT ON已设置,它根本不会被调用。
  • 如果 SET NOCOUNT OFF已设置,它将为批处理中的每个语句调用。

  • (边栏:看起来 StatementCompleted 正是 TDS 协议(protocol)在提及 DONE_IN_PROC 事件时所谈论的内容;请参阅 MSDN 上的 SET NOCOUNT 命令的 Remarks。)

    就个人而言,我在自己的 SQLCMD.EXE 的“克隆”中成功地使用了这种方法。

    更新 : 需要注意的是,这种方法(当然)需要您手动拆分 GO 处的输入脚本/语句。分隔符,因为你又回到了使用 SqlCommand.Execute*()它不能一次处理多个批处理。为此,有多种选择:
  • 在以 GO 开头的行上手动拆分输入(警告:GO 可以像 GO 5 一样调用,例如,执行前一批 5 次)。
  • 使用 ManagedBatchParser类/库来帮助您将输入拆分为单个批处理,尤其是实现 ICommandExecutor.ProcessBatch使用上面的代码(或类似的代码)。

  • 我选择了后一个选项,这是相当多的工作,因为它没有很好的文档记录并且示例很少(谷歌一下,你会找到一些东西,或者使用反射器来查看 SMO-Assemblies 如何使用该类) .

    使用 ManagedBatchParser 的好处(也可能是负担)也就是说,它还将为您解析 T-SQL 脚本的所有其他构造(用于 SQLCMD.EXE )。其中: :setvar , :connect , :quit等。您不必实现相应的 ICommandExecutor成员,当然,如果您的脚本不使用它们。但请注意,您可能无法执行“任意”脚本。

    好吧,那是不是把你放了。从如何打印“...行受影响”的“简单问题”到以稳健和通用的方式进行操作并非易事(考虑到所需的背景工作)。 YMMV,祝你好运。

    ManagedBatchParser 使用更新

    似乎没有关于如何实现 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() 返回的 block 所以这样
    解析器仍然可以使用它们(看起来它们需要完整的语句,
    这首先会破坏解析的目的......)。

    关于c# - SSMS SMO 对象 : Get query results,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12154291/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com