C# 使用ODBC返回SQL Server结果集时出错

C# 使用ODBC返回SQL Server结果集时出错,c#,sql-server,odbc,C#,Sql Server,Odbc,我正在将现有应用程序从Sybase转换为SQL Server 2008。应用程序使用ODBC连接到数据库。简单地更改连接字符串对大多数应用程序功能都有效,但有一个bug让我感到困惑。我创建了一个简单的例子来说明这个bug 我有一个存储过程: create procedure dbo.test_sel as begin create table #cfg ( Name varchar(100) NULL, Dscr varchar(50) NULL ) i

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

我有一个存储过程:

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
以及执行存储过程并将结果加载到数据表中的代码:

{
    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为空(不返回结果集)

现在,如果我注释掉存储过程中的
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());
}
现在可以了,但如果我能帮上忙的话,我宁愿不修改代码,因为应用程序需要在两个数据库上都工作


有人能提出为什么原始代码不起作用吗?这看起来真的很简单,应该可以正常工作。

有两个选项可以用来实现这一点(对我来说,这似乎是一个错误,因为
OdbcDataAdapter
SqlDataAdapter
都应该同样工作):

1) 在过程开始时,在
begin
关键字add之后

set nocount on
2) 使用以
DataSet
为参数的
Fill
方法重载,而不是以
DataTable
为参数的方法重载

MSDN声明:以DataTable为参数的填充重载只获得第一个结果


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

有两个选项可用于执行此操作(对我来说,这似乎是一个错误,因为
OdbcDataAdapter
SqlDataAdapter
Fill
应该同样工作):

1) 在过程开始时,在
begin
关键字add之后

set nocount on
2) 使用以
DataSet
为参数的
Fill
方法重载,而不是以
DataTable
为参数的方法重载

MSDN声明:以DataTable为参数的填充重载只获得第一个结果


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

只是从ODBC的角度添加到Ivan G的答案中。在ODBC术语中,当nocount处于禁用状态时,过程中的每个insert/update/delete/select将作为单独的结果集。在ODBC术语中,您可以调用SQLMoreResults来遍历这些结果集,这样您就可以找到受影响行的计数。非常感谢,在存储过程体的顶部添加SET NOCOUNT ON可以解决此问题。只需从ODBC的角度添加到Ivan G的答案中即可。在ODBC术语中,当nocount处于禁用状态时,过程中的每个insert/update/delete/select将作为单独的结果集。在ODBC术语中,您可以调用SQLMoreResults来遍历这些结果集,这样您就可以找到受影响行的计数。非常感谢,在存储过程体的顶部添加SET-NOCOUNT ON可以解决此问题。