2

考虑以下存储过程:

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 ?

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

4

4 回答 4

2

You can embed the query in an 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

There are however some queries where this won't fly.

  • Multiple statements
  • Queries terminated with ;
  • Queries that uses CTE's

There might be more but these are the ones I can think of right now.

Update:

You could try to use 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

I have never used this in productions but from the tests I made i looks like it should work with SP's, CTE's and multiple lines.

You have to allow ad hoc distributed queries.

于 2012-11-05T21:26:47.847 回答
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
于 2012-11-05T20:53:50.417 回答
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 之外也可用。您必须显式删除该表。

于 2012-11-06T10:50:13.907 回答
0

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

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 分布式查询。
  3. 我必须与on@sql一起使用变量,因为我无法以另一种方式在内部使用变量,因此这会在 an 上生成动态 SQL,这在性能方面非常糟糕。sp_executesqlOPENROWSETOPENROWSETOPENROWSET

我确实使用以下脚本重新配置服务器:

sp_configure 'Ad Hoc Distributed Queries', 1;
RECONFIGURE;
GO
于 2012-11-07T13:23:14.683 回答