web-dev-qa-db-fra.com

Puis-je créer une fonction à usage unique dans un script ou une procédure stockée?

Dans SQL Server 2005, existe-t-il le concept d'une fonction à usage unique ou d'une fonction locale déclarée à l'intérieur d'un script SQL ou d'une procédure stockée? J'aimerais rédiger un peu de complexité dans un script que j'écris, mais cela nécessiterait de pouvoir déclarer une fonction.

Juste curieux.

93
Mark Carpenter

Tu peux appeler CREATE Function près du début de votre script et DROP Function Près de la fin.

61
Joel Coehoorn

Vous pouvez créer des procédures stockées temporaires telles que:

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

dans un script SQL, mais pas les fonctions. Vous pouvez aussi avoir le magasin proc qui en résulte dans une table temporaire, puis utiliser ces informations plus tard dans le script.

78
Ron Savage

Common Table Expressions vous permettent de définir ce que sont essentiellement des vues qui ne durent que dans le cadre de vos instructions select, insert, update et delete. Selon ce que vous devez faire, ils peuvent être extrêmement utiles.

23
Welbog

Je sais que je pourrais être critiqué pour avoir suggéré SQL dynamique, mais c'est parfois une bonne solution. Assurez-vous simplement de bien comprendre les implications en termes de sécurité avant d’envisager cela.

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

Ce qui suit est ce que j’ai utilisé j’ai utilisé dans le passé pour répondre à la nécessité d’une FDU scalaire en MS SQL:

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

Cette approche qui utilise une variable globale pour la procédure vous permet d’utiliser la fonction non seulement dans vos scripts, mais également dans vos besoins en SQL dynamique.

4
Gregory Hart

Dans les scripts, vous avez plus d'options et une meilleure idée de la décomposition rationnelle. Examinez le mode SQLCMD (Menu Requête -> mode SQLCMD), plus particulièrement les commandes: setvar et: r.

Dans une procédure stockée, vos options sont très limitées. Vous ne pouvez pas créer définir une fonction directement avec le corps d'une procédure. Le mieux que vous puissiez faire est quelque chose comme ceci, avec du SQL dynamique:

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

Ceci se rapproche d'une fonction temporaire globale, si une telle chose existait. Il est toujours visible par les autres utilisateurs. Vous pouvez ajouter le @@ SPID de votre connexion pour personnaliser le nom, mais le reste de la procédure nécessiterait également l'utilisation de SQL dynamique.

3
Peter Radocchia