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 つのデータセットを返します。1 つはexec sp_executesql @p_SqlStatementデータを含み、もう 1 つは 1 または 0 です。最初のデータセットを抑制する方法はありますか? つまり、このストアド プロシージャが 1 または 0 のみを返す可能性はありますか?

RAISERROR( 'MyError', 18, 1 )の直後に追加してexec sp_executesql @p_SqlStatementから、catch ブロックで何か他のものを選択しようとしましたが、最初の結果セットは常にストアド プロシージャの呼び出し元に返されます...

4

4 に答える 4

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を使用するクエリ

もっとあるかもしれませんが、これらは私が今考えることができるものです。

アップデート:

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、および複数のラインで動作するはずであるように見えます。

アドホック分散クエリを許可する必要があります。

于 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. サーバーでアドホック分散クエリを有効にする必要があります。
  3. 内部で変数を別の方法で使用できなかったため、変数を on@sqlと一緒に使用する必要があります。これにより、 で動的 SQL が作成され、パフォーマンスが大幅に低下します。sp_executesqlOPENROWSETOPENROWSETOPENROWSET

次のスクリプトを使用してサーバーを再構成します。

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