Sql 我可以在脚本或存储过程中创建一次性使用函数吗?

Sql 我可以在脚本或存储过程中创建一次性使用函数吗?,sql,sql-server,sql-server-2005,tsql,scripting,Sql,Sql Server,Sql Server 2005,Tsql,Scripting,在SQLServer2005中,是否有一次性使用的概念,或在SQL脚本或存储过程中声明的本地函数?我想从我正在编写的脚本中抽象出一些复杂性,但这需要能够声明函数 只是好奇。您可以在脚本开头附近调用CREATE Function,在脚本结尾附近调用DROP Function。让您定义哪些视图本质上只在select、insert、update和delete语句的范围内有效。根据您需要执行的操作,它们可能非常有用。您可以创建以下临时存储过程: create procedure #mytemp as b

在SQLServer2005中,是否有一次性使用的概念,或在SQL脚本或存储过程中声明的本地函数?我想从我正在编写的脚本中抽象出一些复杂性,但这需要能够声明函数


只是好奇。

您可以在脚本开头附近调用
CREATE Function
,在脚本结尾附近调用
DROP Function

让您定义哪些视图本质上只在select、insert、update和delete语句的范围内有效。根据您需要执行的操作,它们可能非常有用。

您可以创建以下临时存储过程:

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

在SQL脚本中,但不是函数。您可以让proc将其结果存储在一个临时表中,然后在脚本的后面使用该信息。

在脚本中,您有更多的选项,并且可以更好地进行rational分解。查看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。

我知道我可能会因为建议使用动态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'

以下是我过去在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


这种方法在过程中使用全局变量,使您不仅可以在脚本中使用该函数,还可以在动态SQL需求中使用该函数。

我打算建议这样做。只要小心你的脚本完成;如果它中止,您仍然可以在数据库中使用该函数。您可以在每次运行之前进行if EXISTS检查,并在找到任何内容时删除。@chocojosh,如果将其包装到事务中,应该可以。如果事务爆炸,函数不应该在数据库中。@JoelCoehoorn:这仍然需要写入权限。请注意,这在函数内部不起作用-函数内部不允许使用临时函数。请看:如果没有函数,可能有更好的方法来做您想要做的事情。也许你应该发布一段你想变成函数的代码片段?你是不是在动态生成一个函数,所以每次都不一样?如果你的函数总是一样的,那就把它放在数据库里吧。我试图这样做是为了让查询更具可读性。创建大量查询的想法很难维护。这应该被认为是正确的答案。被接受的答案不是线程安全的。这取决于您试图做什么。我发现这个问题是因为我正在编写一个数据播种器,我不想将10行合并重复30次。我不关心线程安全,CTEs对我来说不起作用。我认为这个答案,以及它是正确答案的断言,忽略了问题是寻找一个临时函数,而不是临时表。除非我遗漏了一些(并非罕见的)东西,否则CTE可以与temp表相比较。函数可以接受参数,而CTE不能。CTE和temp存储过程之间有很多不同之处(这在这里是正确的答案)。对于初学者来说,CTE只存在于单个语句中,而temp变量可以在整个脚本中使用。其他差异包括:(1)CTE不能容纳SP可以容纳的相同逻辑,(2)CTE不能接受变量。CTE只是一种语法糖,它允许您更轻松地构建嵌套表表达式,以便在语句中使用。即使如此,如果你不知道这些警告,它们在性能上也是危险的。这应该是答案。如果只使用连接作用域临时(single#),这是真正的一次性使用,并且有绕过sql用户限制的好处。那么它是如何使用的呢?这不是select into表达式中使用的过程名称的输入错误吗?当我删除
BEGIN
关键字时,我可以从示例存储过程中获得结果,并将
END
关键字替换为
GO
。OP要求使用临时函数,至少SQL server 2012不允许使用函数的#-语法。仅限过程。这在脚本中不起作用,可能仍需要权限。为了避免重复段,SQL的唯一选项是WITH语句。