-->

SSMS对象SMO:获取查询结果(SSMS SMO Objects: Get query resul

2019-09-21 19:08发布

我碰到这个教程,以了解如何与GO语句执行SQL脚本。
现在,我想知道我能做得到的消息TAB的输出。

随着几个GO语句,输出会是这样:
1行受影响
912行受影响
...

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

Answer 1:

最简单的事情是可能只打印你回来了数量ExecuteNonQuery

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

这应该工作,但不会兑现SET NOCOUNT当前会话/范围的设置。

否则你会像你那样做将与“普通” 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,使用)。
  • 如果SET NOCOUNT ON设置,它不会在所有调用。
  • 如果SET NOCOUNT OFF设置,它会被称为一个批次内的每个语句。

(边栏:它看起来像StatementCompleted正是当有关TDS协议谈判DONE_IN_PROC提到事件;见备注 MSDN上的SET NOCOUNT命令。)

就个人而言,我已经使用在SQLCMD.EXE我自己的“克隆”成功的这种做法。

更新 :应该指出的是,这种方法(当然)需要您手动在拆分输入脚本/报表GO分离器,因为你回来使用SqlCommand.Execute*()不能同时处理多批。 对于这一点,可以有多种选择:

  • 手动分割上开始用线条输入GO (警告: GO可以称为像GO 5 ,例如,以执行前一批5次)。
  • 使用ManagedBatchParser类/库,帮助您拆分输入单个批次,特别是实施ICommandExecutor.ProcessBatch与上面的代码(或类似的东西它)。

我选择后者选项,这是相当一些工作,因为它不是非常有据可查和例子并不多见(google了一下,你会发现一些东西,或者使用反射镜看到SMO组件如何使用这些类) 。

使用的好处(也许负担) ManagedBatchParser是,它还将解析T-SQL脚本的所有其他结构(用于SQLCMD.EXE )为您。 包括: :setvar:connect:quit等不必执行相应的ICommandExecutor会员,如果你的脚本不使用它们,当然。 不过,别忘了,你会可能无法执行“乱”的脚本。

嗯,是这样做就把你。 从如何打印“......受影响的行”的事实,这是不平凡的一个强大的和一般的方式做了“简单问题”(给出所需的后台工作)。 因人而异,好运气。

更新上ManagedBatchParser用法

似乎是有关如何实现没有好documenation或例如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 )有他们阅读全文一次到内存的问题。 我有一种情况是炸毁,具有生成的gazillions一个巨大的(!)脚本INSERT语句。 尽管我不认为这是一个实际问题, SQLCMD.EXE可以处理它。 但对我的生活,我无法弄清楚究竟如何,则需要形成返回块IBatchParser.GetContent()这样分析器仍然能够与他们合作(它看起来像他们将需要完整的语句,这会有点击败解析的目的摆在首位...)。



文章来源: SSMS SMO Objects: Get query results