Могу ли я создать функцию одноразового использования в скрипте или хранимой процедуре? - PullRequest
90 голосов
/ 11 июня 2009

В SQL Server 2005 существует ли концепция одноразового использования или локальная функция, объявленная внутри сценария SQL или хранимой процедуры? Я хотел бы абстрагироваться от некоторой сложности в сценарии, который я пишу, но это потребовало бы возможности объявления функции.

Просто любопытно.

Ответы [ 6 ]

76 голосов
/ 11 июня 2009

Вы можете создавать временные хранимые процедуры, такие как:

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

в сценарии SQL, но не в функциях. Вы можете хранить в proc процесс его результат во временной таблице, а затем использовать эту информацию позже в скрипте.

61 голосов
/ 11 июня 2009

Вы можете позвонить CREATE Function в начале вашего скрипта и DROP Function в конце.

21 голосов
/ 11 июня 2009

Общие табличные выражения позволяют вам определить, какие по сути представления являются последними только в пределах ваших операторов выбора, вставки, обновления и удаления. В зависимости от того, что вам нужно сделать, они могут быть очень полезны.

10 голосов
/ 23 сентября 2015

Я знаю, что меня могут критиковать за предложение динамического 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'
3 голосов
/ 29 августа 2016

Ниже приведено то, что я использовал в прошлом для удовлетворения потребности в скалярной пользовательской функции в 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

Этот подход, использующий глобальную переменную для PROCEDURE, позволяет использовать функцию не только в ваших сценариях, но и в ваших потребностях в динамическом SQL.

3 голосов
/ 12 июня 2009

В сценариях у вас есть больше возможностей и лучший способ рационального разложения. Посмотрите на режим 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.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...