如何在存储过程中仅返回单个结果集

时间:2012-11-05 20:42:02

标签: sql-server-2008 tsql

考虑以下存储过程:

create procedure [dbo].[MyTest] ( @p_SqlStatement nvarchar(max) )
as
begin

    exec sp_executesql @p_SqlStatement

    if @@ROWCOUNT = 1
    begin
      select 1;
    end
    else if @@ROWCOUNT <> 1
    begin
      select 0;
    end

end

此存储过程当前返回2个数据集,一个包含exec sp_executesql @p_SqlStatement数据,另一个数据集为1或0.有没有办法抑制第一个数据集?我的意思是,这个存储过程是否可能只返回1或0?

我尝试在RAISERROR( 'MyError', 18, 1 )之后添加exec sp_executesql @p_SqlStatement,然后在catch块中选择其他内容,但第一个结果集总是返回给我的存储过程调用者...

4 个答案:

答案 0 :(得分:2)

您可以将查询嵌入if exists(

alter procedure [dbo].[MyTest] ( @p_SqlStatement nvarchar(max) )
as
begin
    set @p_SqlStatement = 'if exists('+@p_SqlStatement+') select 1 else select 0'

    exec sp_executesql @p_SqlStatement
end

但是有一些问题会导致无法飞行。

  • 多个陈述
  • 查询以;
  • 终止
  • 使用CTE's
  • 的查询

可能会有更多,但这些是我现在能想到的。

<强>更新

您可以尝试使用openrowset

alter procedure [dbo].[MyTest] ( @p_SqlStatement nvarchar(max) )
as
begin
  declare @S nvarchar(max)
  set @S = 
    'if exists(
              select *
              from openrowset(
                              ''SQLNCLI'',
                              ''Server=localhost;Trusted_Connection=yes;'',
                              '+quotename(@p_SqlStatement, '''')+'
                             ) as T
              )
      select 1
    else
      select 0'

  exec (@S)
end

我从来没有在制作过程中使用过这个,但是从我做的测试来看,它看起来应该适用于SP,CTE和多行。

您必须允许ad hoc distributed queries

答案 1 :(得分:0)

您可以尝试使用NOCOUNT语句(http://msdn.microsoft.com/en-us/library/ms189837.aspx

create procedure [dbo].[MyTest] ( @p_SqlStatement nvarchar(max) )
as
begin

SET NOCOUNT ON;

    exec sp_executesql @p_SqlStatement

    if @@ROWCOUNT = 1
    begin
      select 1;
    end
    else if @@ROWCOUNT <> 1
    begin
      select 0;
    end

SET NOCOUNT OFF;

end

答案 2 :(得分:0)

尝试这种方法:

declare @mycount bigint

exec sp_executesql N'select @mycount = count(name) from Page where name like ''P%''', N'@mycount bigint OUTPUT', @mycount OUTPUT

select @mycount

您的语句@p_SqlStatement包含计数非常重要。

如果不是这种情况,意味着你想为你遇到的任何SQL运行这个sp,那么这没有用。我认为你无法抑制sp_executesql的输出。

编辑:你也可以试试这个:

declare @mycount bigint

exec sp_executesql N'SELECT * INTO ##MyTempTable from Page where name like ''P%'''

select count(*) from ##MyTempTable 
drop table ##MyTempTable 

这意味着您必须将以下内容添加到每个查询中(不知道这是否适用于sp?)“SELECT * INTO ## MyTempTable FROM” - 这应该不会很难。

“## temptables”是全局范围的临时表。这意味着它们也可以在sp_executesql sp之外使用。您必须明确删除该表。

答案 3 :(得分:0)

除了使用建议的OPENROWSET之外,我找不到任何其他解决方法。但是,我发现了一种与servername / instance无关的方法。我仍然需要重新配置服务器以接受临时分布式查询。这是最终结果:

create procedure [dbo].[MyTest] ( @p_SqlStatement nvarchar(max) )
as
begin

    declare @sql nvarchar(max) = N'SELECT * INTO ##TMP FROM OPENROWSET(''SQLOLEDB'',''Server=' + @@SERVERNAME + ';Trusted_Connection=Yes;'',''' + @p_SqlStatement + ''')';
    exec sp_executesql @sql

    if ( select COUNT(1) from ##TMP ) = 1
    begin
      select 1;
    end
    else
    begin
      select 0;
    end

    drop table ##TMP;

end

此解决方案有其局限性:

  1. @p_SqlStatement中的每一列都必须具有名称
  2. 我必须在我的服务器上启用Ad Hoc Distributed Queries。
  3. 我必须在@sql上使用sp_executesql变量和OPENROWSET,因为我无法以另一种方式在OPENROWSET内使用变量,因此这会产生动态SQL在OPENROWSET,这在性能方面非常糟糕。
  4. 我使用以下脚本重新配置服务器:

    sp_configure 'Ad Hoc Distributed Queries', 1;
    RECONFIGURE;
    GO