12

私の要件に従って関数を作成しようとしています。

しかし、作成またはドロップ#tempTableすると、次のようなエラーが発生します。

関数内での副作用演算子 'drop object' の無効な使用

create私の理解では、関数内で、dropまたはinsert操作を行うことはできません#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、一時テーブルにアクセスしようとすると、次のメッセージが表示されます(など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 に答える