12

我正在尝试根据我的要求创建一个功能。

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

在函数中无效使用副作用运算符“drop object”

我的理解是,我们不能在函数中进行create, droporinsert操作。#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
4

3 回答 3

25

这是正确的 - 你不能有副作用的陈述:

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

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

即使没有您的DROP声明,您会发现任何访问​​临时表的尝试都会给您消息(例如 a 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

没有经过测试或任何东西,但你明白了要点。

于 2012-06-29T19:34:29.953 回答
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
  );

正如乔恩指出的那样,我认为它也可以重写如下,这实际上是我开始编写它的方式,但我无法确认其中任何一个是否真的返回了你试图返回的数据:

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
  );
于 2012-06-29T20:49:38.247 回答
0

去掉#改为使用@其他方面我没测试过

于 2014-01-24T08:51:03.597 回答