web-dev-qa-db-ja.com

関数からストアドプロシージャを実行する

私はこれが死ぬように頼まれたことを知っています。そして、SQL Serverがあなたにそれをさせない理由を知っています。

しかし、拡張ストアドプロシージャを使用する以外に、これに対する回避策はありますか?

そして、関数をプロシージャに変換するように言わないでください...

だから私が本当に求めているのは、関数内からストアドプロシージャを実行する方法はありますか?

編集:

実証済みのポイント:回避方法はありますが、そうです[〜#〜] wrong [〜#〜]しません。ストアドプロシージャに変更し、別の場所で実行します。

45
Smur

編集:私はこれを試していないので、それを保証することはできません!そして、あなたはこれをするべきではないことを既に知っているので、それをしないでください。しかし...

ここを見てみてください: http://sqlblog.com/blogs/denis_gobo/archive/2008/05/08/6703.aspx

重要なビットは、私があなたの目的のために微調整しようとしたこのビットです:

DECLARE @SQL varchar(500)

SELECT @SQL = 'osql -S' +@@servername +' -E -q "exec dbName..sprocName "'

EXEC master..xp_cmdshell @SQL
26
Tom Chantler

関数には、テーブルの内容を変更するなどの副作用はありません。

ストアドプロシージャは。

関数がストアドプロシージャを呼び出した場合、その関数は副作用を持つことができます。


したがって、申し訳ありませんが、いいえ、関数からストアドプロシージャを呼び出すことはできません。

11
MatBailie

OPENQUERYとxp_cmdshellの使用に加えて、SQLCLR(SQL Serverの「CLR統合」機能)を使用することもできます。 SQLCLRオプションは他の2つの方法よりも安全であるだけでなく、現在のセッションでストアドプロシージャを呼び出すことができるという潜在的な利点もあります次のようなセッションベースのオブジェクトまたは設定へのアクセス

  • 一時テーブル
  • 一時ストアドプロシージャ
  • CONTEXT_INFO

これは、「context connection = true;」を使用して実現できます。 ConnectionStringとして。 T-SQLユーザー定義関数に課された他のすべての制限が適用されることに注意してください(つまり、副作用はありません)。

通常の接続を使用する場合(つまり、コンテキスト接続を使用しない場合)、OPENQUERYメソッドとxp_cmdshellメソッドを使用する場合と同様に、独立した呼び出しとして動作します。

[〜#〜] however [〜#〜]、ストアドプロシージャを呼び出す関数を使用する場合は、 3つのメソッドのうち、使用する3つのうちいずれか)を複数の行に影響するステートメントで使用すると、行ごとに1回動作することは期待できません。 @MatBailieの回答に関するコメントで@MartinSmithが言及したように、クエリオプティマイザーは、関数の実行のタイミングまたは数を保証しません。ただし、SET @Variable = function();ステートメントまたはSELECT * FROM function();クエリで使用している場合は、問題ありません。

.NET/C#SQLCLRユーザー定義関数を使用してストアドプロシージャを実行する例は、次の記事(私が書いた記事)に示されています。

SQLCLRレベル2への階段:ストアドプロシージャと関数のサンプル

1
Solomon Rutzky

この問題の解決策を見つけました。ストアドプロシージャで「レンダリングされた」SQLを使用して関数またはビューを作成し、通常どおり実行できます。

1.別のsprocを作成する

CREATE PROCEDURE [dbo].[usp_FunctionBuilder]
DECLARE @outerSql VARCHAR(MAX)
DECLARE @innerSql VARCHAR(MAX)

2.関数で実行する動的SQLを構築します(例:ループとユニオンを使用したり、別のsprocを読み取ったり、条件付きSQLのifステートメントやパラメーターを使用したりできます)

SET @innerSql = 'your sql'

3. @innerSqlを関数作成ステートメントでラップし、@ innerSqlで使用した外部パラメーターを定義して、生成された関数に渡すことができるようにします。

SET @outerSql = 'CREATE FUNCTION [dbo].[fn_GeneratedFunction] ( @Param varchar(10))
RETURNS TABLE
AS
RETURN
' + @innerSql;


EXEC(@outerSql)

これは単なる擬似コードですが、このソリューションは、リンクサーバーの制限、パラメーター、動的SQLの機能、動的サーバー/データベース/テーブル名、ループなど、多くの問題を解決します。

ニーズに合わせて微調整する必要があります(例:関数の戻り値を変更する)

0
C Rudolph

別の可能な回避策は次のとおりです。

if exists (select * from master..sysservers where srvname = 'loopback')
    exec sp_dropserver 'loopback'
go
exec sp_addlinkedserver @server = N'loopback', @srvproduct = N'', @provider = N'SQLOLEDB', @datasrc = @@servername
go

create function testit()
    returns int
as
begin
    declare @res int;
    select @res=count(*) from openquery(loopback, 'exec sp_who');
    return @res
end
go

select dbo.testit()

xp_cmdshellほど怖いわけではありませんが、実際には 意味が多すぎます もあります。

0
Vadzim