Pregunta ¿Puedo crear una función de uso único en un script o procedimiento almacenado?


En SQL Server 2005, ¿existe un concepto de uso único o función local declarada dentro de un script SQL o procedimiento almacenado? Me gustaría abstraer algo de complejidad en un script que estoy escribiendo, pero requeriría poder declarar una función.

Sólo curioso.


76
2018-06-11 14:30


origen


Respuestas:


Puedes llamar CREATE Function cerca del comienzo de su secuencia de comandos y DROP Function cerca del final.


52
2018-06-11 14:32



Puede crear procedimientos almacenados temporales como:

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

en una secuencia de comandos SQL, pero no en las funciones. Sin embargo, podrías hacer que el proc almacene su resultado en una tabla temporal, luego usa esa información más adelante en el script.


63
2018-06-11 14:37



Expresiones de tabla comunes le permite definir lo que esencialmente son vistas que duran solo dentro del alcance de sus declaraciones de selección, inserción, actualización y eliminación. Dependiendo de lo que necesite hacer, pueden ser terriblemente útiles.


20
2018-06-11 14:35



Sé que podría ser criticado por sugerir SQL dinámico, pero a veces es una buena solución. Solo asegúrese de comprender las implicaciones de seguridad antes de considerar esto.

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'

6
2017-09-23 17:23



En las secuencias de comandos tiene más opciones y una mejor oportunidad de descomposición racional. Mire en el modo SQLCMD (Menú de consulta -> modo SQLCMD), específicamente los comandos: setvar y: r.

Dentro de un procedimiento almacenado, sus opciones son muy limitadas. No puede crear definir una función directamente con el cuerpo de un procedimiento. Lo mejor que puedes hacer es algo como esto, con SQL dinámico:

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

Esto se aproxima a una función temporal global, si tal cosa existió. Todavía es visible para otros usuarios. Podría agregar @@ SPID de su conexión para unificar el nombre, pero eso requeriría que el resto del procedimiento también use SQL dinámico.


2
2018-06-12 05:29



Lo siguiente es lo que he usado en el pasado para lograr la necesidad de una UDF Scalar 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

Este enfoque que utiliza una variable global para el PROCEDIMIENTO le permite hacer uso de la función no solo en sus scripts, sino también en sus necesidades de SQL dinámico.


2
2017-08-29 20:49