2012-06-29 11 views
7

Sto tentando di creare una funzione secondo le mie esigenze.Creare, rilasciare e inserire una tabella temporanea in una funzione definita dall'utente

Ma, quando sono la creazione o cadere #tempTable, si sta dando un errore come:

uso non valido di un operatore di side-effettuando 'oggetto drop' all'interno di una funzione

la mia comprensione è che non possiamo avere operazioni create, drop o insert su #temptable in una funzione.

È corretto?

My 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 
+1

bit confusi sul tuo SQL. Come si seleziona da #tempTable dopo averlo eliminato, non viene mai ricreato. –

+0

Si prega di trovare il post aggiornato –

+0

Se si desidera aiutare a risolvere questo problema, si prega di spiegare il punto del #temptable all'interno della funzione. Inoltre cosa fare con il parametro Id. –

risposta

19

Questo è corretto - non si può avere collaterali effettuare dichiarazioni:

Da qui: http://msdn.microsoft.com/en-us/library/aa175085(v=sql.80).aspx

Le dichiarazioni in un blocco BEGIN ... END non può avere effetti collaterali. Gli effetti collaterali delle funzioni sono qualsiasi modifica permanente allo stato di una risorsa che ha un ambito esterno alla funzione, ad esempio una modifica a una tabella di database. Le uniche modifiche che possono essere apportate dalle istruzioni nella funzione sono le modifiche agli oggetti locali alla funzione , ad esempio cursori o variabili locali. Le modifiche alle tabelle del database , le operazioni sui cursori che non sono locali alla funzione , l'invio di e-mail, il tentativo di modifica del catalogo e che genera un set di risultati restituito all'utente sono esempi di azioni che non possono essere eseguite in una funzione.

Cosa si dovrebbe trovare, anche senza la vostra DROP economico, è che ogni tentativo di accedere a una tabella temporanea vi darà il messaggio (ad esempio un SELECT ... INTO #TMP):

Impossibile accedere tabelle temporanee dall'interno una funzione

Come sottolinea @Dems, è possibile utilizzare le variabili di tabella. Poiché si tratta di variabili, sono incluse nell'ambito della funzione e pertanto non hanno effetto collaterale.

La funzione potrebbe funzionare come:

... 

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 

non testato o altro, ma si ottiene l'essenza.

+3

Ma è possibile utilizzare le variabili di tabella. Quale sarebbe un fatto utile da aggiungere alla tua risposta per aiutare l'OP a risolvere il suo problema * (piuttosto che sapere perché è un problema) *;) – MatBailie

+0

@Dems: buon punto - aggiornato con maggiori informazioni. –

+0

Dopo aver letto la documentazione MSDN, mi sono chiesto: è possibile modificare i dati reali da una tabella ('INSERT' /' UPDATE'/'DELETE') chiamando una' Stored Procedure' nella 'funzione'? Suppongo che non puoi, ma preferirei essere sicuro che verrà prodotto un errore. Potresti dirmi se lo sai? :) –

2

Non ho idea del motivo per cui è necessaria una tabella #temp in questa funzione o perché si tratta di un TVF a più istruzioni.Di seguito sarà molto più efficiente (anche se non capisco lo scopo del parametro @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 
); 

Come Jon ha sottolineato, io penso potrebbe anche essere riscritta come segue, ed è in realtà come ho iniziato a scrivere, ma non ho alcun modo di confermare se uno di questi in realtà restituisce i dati che si sta cercando di tornare:

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 
); 
+0

Vero - il tavolo temporaneo è un po '"di lusso" in questo caso, ma è un punto utile da coprire in ogni caso. (inoltre è necessario un alias sul conteggio interno). –

+0

@Jon ID e nome provengono da diverse tabelle. Non conosco lo schema oi dati, quindi ho cercato di rimanere fedele alla query originale. –

0

Rimuovere # invece utilizzare @ non ho ancora testato altro aspetto

Problemi correlati