web-dev-qa-db-ja.com

スクリプトまたはストアドプロシージャで1回限りの関数を作成できますか?

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

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

93
Mark Carpenter

スクリプトの先頭近くでCREATE Function、末尾近くでDROP Functionを呼び出すことができます。

61
Joel Coehoorn

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

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

関数ではなく、SQLスクリプトで。ただし、結果を一時テーブルに保存し、その後スクリプトでその情報を使用することもできます。

78
Ron Savage

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

23
Welbog

動的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'
10
Tmdean

以下は、MS SQLでScalar 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のニーズでも関数を使用できます。

4
Gregory Hart

スクリプトには、より多くのオプションがあり、合理的な分解のより良いショットがあります。 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
Peter Radocchia