1

我正在将现有应用程序从 Sybase 转换为 SQL Server 2008。该应用程序使用 ODBC 连接到数据库。简单地更改连接字符串对大多数应用程序功能都有效,但有一个错误让我感到困惑。我创建了一个显示错误的简单示例。

我有一个存储过程:

create procedure dbo.test_sel
as 
begin
  create table #cfg
  (
    Name  varchar(100) NULL,
    Dscr  varchar(50)  NULL
  )

  insert #cfg(Name, Dscr) 
  values('Config', 'Config description')

  select COUNT(*) as [Count] from #cfg

  return 0
end

以及执行存储过程并将结果加载到 DataTable 中的代码:

{
    OdbcCommand cmd = new OdbcCommand("test_sel", new OdbcConnection("Driver={SQL Server};Server=xxx;Database=xxx;Uid=xxx;Pwd=xxx"));

    DataTable dt = new DataTable();

    OdbcDataAdapter da = new OdbcDataAdapter(cmd);

    using (cmd.Connection)
    {
        da.Fill(dt);
    }

    MessageBox.Show(dt.Rows.Count.ToString());
}

我希望消息显示值 1 并且 DataTable 包含单行。但是 DataTable 是空的(不返回结果集)。

现在,如果我注释掉insert存储过程中的语句并重新运行代码,那么我会得到一个返回的结果集,其中包含一行、一列名为 count 的值为 0。

我已经尝试了存储过程的许多变体,例如使用永久表而不是临时表,但每次发生相同的事情时 - 插入会阻止存储过程返回结果集。

将 ODBC 驱动程序更改为 SQL Server 2008 没有任何区别。该代码在使用 Sybase 和在 MS SQL Server Management Studio 中运行时按预期工作。

谷歌搜索后,我尝试了以下代码:

{
    SqlCommand cmd = new SqlCommand("test_sel", new SqlConnection("Server=xxx,5100;Database=xxx;User ID=xxx;Password=xxx"));

    DataTable dt = new DataTable();

    SqlDataAdapter da = new SqlDataAdapter(cmd);

    using (cmd.Connection)
    {
        da.Fill(dt);
    }

    MessageBox.Show(dt.Rows.Count.ToString());
}

现在这可行,但如果我能提供帮助,我宁愿不为此更改代码,因为该应用程序需要在两个数据库上运行。

谁能建议为什么原始代码不起作用?看起来很简单的东西应该可以正常工作。

4

1 回答 1

1

您可以使用 2 个选项来完成这项工作(对我来说,这似乎是错误,因为Fill两者都OdbcDataAdapter应该SqlDataAdapter同样工作):

1)在程序的开始begin关键字后添加

set nocount on

2)使用作为参数的Fill方法的重载,而不是采用的方法。DataSetDataTable

MSDN指出:以DataTable为参数的Fill的重载只得到第一个结果

INSERT执行并NOCOUNT关闭时,将返回有关受语句影响的行数的信息。因此,当您关闭此选项时,将报告 2 次行数(您可以在 SSMS 的“消息”窗口中检查),一次用于 INSERT,第二次用于 SELECT。似乎第一行计数(来自 INSERT)以某种方式被解释为第一个结果集,该行计数INSERT不是指语句SELECT,因此没有要返回的行。

于 2013-02-22T09:07:03.220 回答