在用户定义的函数中创建,删除和插入临时表

时间:2012-06-29 19:26:09

标签: sql-server function

我正在尝试按照我的要求创建一个功能。

但是,当我创建或删除#tempTable时,它会给出错误:

  

在函数

中无效使用副作用运算符'drop object'

我的理解是,我们无法在create函数中执行dropinsert#temptable操作。

这是对的吗?

我的SQL:

CREATE FUNCTION [dbo].[RT_ResultFunction]
(
    Id VARCHAR(4000)
)
RETURNS @RT_ResultFunction TABLE 
(   
    Id VARCHAR(20)
    , Name varchar(20)
    ,Balance Int
)
AS
BEGIN
    IF OBJECT_ID('tempdb..#tempTable') IS NOT NULL  
       DROP TABLE #tempTable

    SELECT Id, COUNT(Balance) 
    INTO  #tempTable
    'Balance' FROM Table1

    INSERT  @RT_ResultFunction 
        SELECT T1.ID,T1,NAME,T2,Balance 
        FROM    Table2 T1, 
                #tempTable T2
        WHERE T1.ID = T2.ID

    RETURN
END

3 个答案:

答案 0 :(得分:19)

这是正确的 - 你不能有副作用声明:

从这里开始:http://msdn.microsoft.com/en-us/library/aa175085(v=sql.80).aspx

  

BEGIN ... END块中的语句不能有任何副作用。   功能副作用是对状态的任何永久性改变   具有函数外部范围的资源,例如修改   到数据库表。可以做出的唯一改变   函数中的语句是对本地对象的更改   函数,例如本地游标或变量。修改为   数据库表,对非本地游标的操作   功能,发送电子邮件,尝试修改目录,以及   生成返回给用户的结果集是示例   无法在函数中执行的操作。

即使没有DROP语句,您会发现,任何访问临时表的尝试都会为您提供消息(例如SELECT ... INTO #TMP):

  

无法从函数中访问临时表

正如@Dems指出的那样,你可以使用表变量。因为这些是变量,所以它们在函数范围内,因此不会产生副作用。

您的功能可能会运行:

...

BEGIN
    DECLARE @tempTable table (id varchar(20), rows int)

    insert @tempTable
    SELECT Id, COUNT(Balance) 
    FROM Table1

    INSERT  @RT_ResultFunction 
        SELECT T1.ID,T1,NAME,T2,Balance 
        FROM    Table2 T1, 
                @tempTable T2
        WHERE T1.ID = T2.ID

    RETURN END

没有经过测试或其他任何事情,但你得到了要点。

答案 1 :(得分:2)

我不知道为什么你需要在这个函数中使用#temp表,或者为什么它首先是一个多语句TVF。以下将更有效(虽然我不理解@Id参数的目的):

CREATE FUNCTION [dbo].[RT_ResultFunction]
(
    @Id VARCHAR(4000)
)
RETURNS TABLE
WITH SCHEMABINDING 
AS
  RETURN 
  (
    SELECT T2.ID, T2.NAME, T1.Balance
    FROM
    (
      SELECT ID, Balance = COUNT(Balance) 
        FROM dbo.Table1 
        GROUP BY ID
    ) AS T1
    INNER JOIN dbo.Table2 AS T2
    ON T1.ID = T2.ID
  );

正如Jon指出的那样,我认为它也可以重写如下,实际上我是如何开始编写它的,但我无法确认其中任何一个是否实际返回您尝试返回的数据:

CREATE FUNCTION [dbo].[RT_ResultFunction]
(
    @Id VARCHAR(4000)
)
RETURNS TABLE
WITH SCHEMABINDING 
AS
  RETURN 
  (
    SELECT T2.ID, T2.NAME, Balance = COUNT(T1.Balance)
    FROM dbo.Table1 AS T1 
    INNER JOIN dbo.Table2 AS T2
    ON T1.ID = T2.ID
    GROUP BY T2.ID, T2.NAME
  );

答案 2 :(得分:0)

删除#而不是使用@ 我没有测试过其他方面