スクリプトまたはストアドプロシージャで使い捨て関数を作成できますか?


109

SQL Server 2005で、SQLスクリプトまたはストアドプロシージャの内部で宣言された、1回限りの使用、つまりローカル関数の概念はありますか?作成しているスクリプトの複雑さを抽象化したいのですが、関数を宣言できる必要があります。

ちょっと興味があるんだけど。


おそらく、関数なしであなたがやりたいことをするためのより良い方法があるでしょう。おそらく、関数にしたいコードのスニペットを投稿する必要がありますか?
DForck42 2009年

関数を動的に生成しているので、毎回異なりますか?機能が常に同じである場合は、データベースに残してください
KM。

1
クエリを読みやすくする方法としてそれを試みました。巨大なクエリを作成するという考えは、維持が難しくなります。
Jp_17年

回答:


65

CREATE Functionスクリプトの最初とDROP Function最後の近くで呼び出すことができます。


6
これを提案するつもりでした。スクリプトが終了するように注意してください。異常終了した場合でも、DBにはその機能が残っています。
チョコジョシュ2009年

6
各実行前にIF EXISTSチェックを実行し、何かが見つかった場合は削除できます。
Adrian Godong

7
@chocojosh、それをトランザクションでラップする場合は問題ありません。トランザクションが爆破する場合、関数はデータベースに存在してはなりません。
Jeff LaFay 2013

12
@JoelCoehoorn:これにはまだ書き込み権限が必要です。
user2284570

2
これは関数内では機能しないことに注意してください-関数内の一時的な関数は許可されていません。参照:technet.microsoft.com/en-us/library/ms191320.aspx#Restrictions
Daniel Neel

95

次のような一時ストアドプロシージャを作成できます。

create procedure #mytemp as
begin
   select getdate() into #mytemptable;
end

SQLスクリプトでは使用できますが、関数では使用できません。ただし、結果を一時テーブルに格納して、後でスクリプトでその情報を使用することもできます。


7
これが答えになるはずです。これは、接続スコープが一時的なもの(単一の#)の場合、本当に使い捨てであり、SQLユーザーの制限を回避できるという利点があります。
2016

それではそれはどのように使用されますか?select into式で使用されるプロシージャ名のタイプミスではないですか?
jgomo3

私は削除するときあなたの例ストアドプロシージャから結果を得ることができるよBEGINキーワードを、と置き換えるENDとキーワードをGO
ジョセフディクストラ2017年

OPは一時的な関数を要求していましたが、少なくともSQL Server 2012では関数の#構文を使用できません。手順のみ。
Erk

これはスクリプト内では機能せず、権限が必要な場合があります。反復セグメントを回避するために、SQLの唯一のオプションはWITHステートメントです。
alex.peter

25

共通テーブル式を使用すると、select、insert、update、およびdeleteステートメントのスコープ内でのみ持続する基本的にビューを定義できます。あなたが何をする必要があるかに応じて、それらはひどく役に立ちます。


5
これは正解として受け入れられるべきです。受け入れられた答えはスレッドセーフではありません。
カリヤン14年

11
あなたがやろうとしていることに依存します。データシーダーを作成していて、10行のMERGE INTOを30回繰り返したくないので、この質問を見つけました。スレッドセーフについては気にせず、CTEは機能しません。
solipsicle 2014年

16
私はこの答え、そしてそれが正しい答えであるという主張は、質問が一時的な表ではなく一時的な関数を探していることを見逃していると思います。(珍しいことではありませんが)何かを見逃していない限り、CTEは一時テーブルに相当します。
JD Long

8
関数は引数を取ることができますが、CTEはできません。
–RăzvanFlavius Panda 2016

4
CTEと一時ストアドプロシージャの間には多くの違いがあります(これがIMOの正解です)。手始めに、CTEは単一のステートメントに対してのみ存在しますが、一時変数はスクリプト全体で使用できます。その他の違いは次のとおりです。(1)CTEはSPと同じロジックを収容できない、(2)CTEは変数を受け入れることができない。CTEは単に構文上の砂糖であり、ステートメントで使用するネストされたテーブル式をより簡単に構築できます。それでも、警告に気付いていない場合、パフォーマンス面で危険な場合があります。
19:02で

12

動的SQLを提案したことで非難されるかもしれませんが、それが良い解決策になることもあります。これを検討する前に、セキュリティへの影響を理解していることを確認してください。

DECLARE @add_a_b_func nvarchar(4000) = N'SELECT @c = @a + @b;';
DECLARE @add_a_b_parm nvarchar(500) = N'@a int, @b int, @c int OUTPUT';

DECLARE @result int;
EXEC sp_executesql @add_a_b_func, @add_a_b_parm, 2, 3, @c = @result OUTPUT;
PRINT CONVERT(varchar, @result); -- prints '5'

4

スクリプトには、より多くのオプションがあり、合理的な分解でより良いショットがあります。SQLCMDモード(クエリメニュー-> SQLCMDモード)、特に:setvarコマンドと:rコマンドを調べます。

ストアドプロシージャ内では、オプションは非常に限られています。プロシージャの本体で関数を直接定義することはできません。あなたができる最善のことは、動的SQLを使用した次のようなものです。

create proc DoStuff
as begin

  declare @sql nvarchar(max)

  /*
  define function here, within a string
  note the underscore prefix, a good convention for user-defined temporary objects
  */
  set @sql = '
    create function dbo._object_name_twopart (@object_id int)
    returns nvarchar(517) as
    begin
      return 
        quotename(object_schema_name(@object_id))+N''.''+
        quotename(object_name(@object_id))
    end
  '

  /*
  create the function by executing the string, with a conditional object drop upfront
  */
  if object_id('dbo._object_name_twopart') is not null drop function _object_name_twopart
  exec (@sql)

  /*
  use the function in a query
  */
  select object_id, dbo._object_name_twopart(object_id) 
  from sys.objects
  where type = 'U'

  /*
  clean up
  */
  drop function _object_name_twopart

end
go

このようなものが存在する場合、これはグローバル一時関数に近似します。他のユーザーには引き続き表示されます。接続の@@ SPIDを追加して名前を一意化することもできますが、その場合、残りの手順でも動的SQLを使用する必要があります。


3

以下は、MS SQLでスカラーUDFの必要性を達成するために過去に使用したものです。

IF OBJECT_ID('tempdb..##fn_Divide') IS NOT NULL DROP PROCEDURE ##fn_Divide
GO
CREATE PROCEDURE ##fn_Divide (@Numerator Real, @Denominator Real) AS
BEGIN
    SELECT Division =
        CASE WHEN @Denominator != 0 AND @Denominator is NOT NULL AND  @Numerator != 0 AND @Numerator is NOT NULL THEN
        @Numerator / @Denominator
        ELSE
            0
        END
    RETURN
END
GO

Exec ##fn_Divide 6,4

PROCEDUREにグローバル変数を使用するこのアプローチでは、スクリプトだけでなく、動的SQLのニーズでも関数を使用できます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.