2009-06-11 11 views
72

In SQL Server 2005, esiste un concetto di utilizzo singolo o funzione locale dichiarata all'interno di uno script SQL o stored procedure? Mi piacerebbe astrarre una certa complessità in uno script che sto scrivendo, ma richiederebbe la possibilità di dichiarare una funzione.Posso creare una funzione usa e getta in uno script o una procedura memorizzata?

Solo curioso. Grazie!!

+0

probabilmente c'è un modo migliore per fare ciò che vuoi senza una funzione. forse dovresti pubblicare uno snippet del codice che vuoi trasformare in una funzione? – DForck42

+0

stai generando una funzione in modo dinamico, quindi è diversa ogni volta? se la tua funzione è sempre la stessa basta lasciarla nel database –

+0

stavo cercando di farlo come un modo per rendere la query più leggibile. L'idea di creare query enormi è difficile da mantenere. –

risposta

50

È possibile chiamare CREATE Function vicino all'inizio del copione e DROP Function vicino alla fine.

+4

Stavo per suggerire questo. Fai solo attenzione che il tuo copione finisca; se si interrompe, avrai ancora la funzione nel DB. – chocojosh

+4

È possibile eseguire un controllo IF EXISTS prima di ogni esecuzione ed eliminare se viene trovato qualcosa. –

+6

@chocojosh, che dovrebbe essere ok se lo si avvolge in una transazione. La funzione non dovrebbe essere nel database se le bombe di transazione. – jlafay

19

Common Table Expressions consente di definire quali sono essenzialmente viste che durano solo nell'ambito delle istruzioni di selezione, inserimento, aggiornamento ed eliminazione. A seconda di cosa devi fare possono essere terribilmente utili.

+3

Questo dovrebbe essere accettato come risposta corretta. La risposta accettata non è infallibile. – kalyan

+4

Dipende da cosa stai cercando di fare. Ho trovato questa domanda perché sto scrivendo una seminatrice di dati e non voglio ripetere 10 righe di MERGE INTO 30 volte. Non mi importa di threadsafe e CTE non funzionerà per me. – solipsicle

+9

Penso che questa risposta, e le asserzioni che è la risposta corretta, manca che la domanda è alla ricerca di una funzione temporanea, non temp TABLE. A meno che non manchi qualcosa (non raro) i CTE sono paragonabili alle tabelle temporanee. –

56

È possibile creare temporanei stored procedure come:

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

in uno script SQL, ma non le funzioni. Potresti avere il proc store come risultato in una tabella temporanea, quindi usarlo successivamente nello script.

+3

Questa dovrebbe essere la risposta. Questo è veramente monouso se solo con connessione scope temporanea (single #), e ha il vantaggio di aggirare le restrizioni dell'utente sql. – Todd

+0

Come si usa allora? Non è un refuso nel nome della procedura utilizzato nella selezione in espressione? – jgomo3

+0

Sono in grado di ottenere risultati dalla stored procedure di esempio quando rimuovo la parola chiave 'BEGIN' e sostituisco la parola chiave' END' con 'GO'. –

2

Negli script hai più opzioni e una migliore possibilità di scomposizione razionale. Esaminare la modalità SQLCMD (Menu query -> Modalità SQLCMD), in particolare i comandi: setvar e: r.

All'interno di una stored procedure le opzioni sono molto limitate. Non è possibile creare definire una funzione direttamente con il corpo di una procedura. Il meglio che puoi fare è qualcosa di simile, con SQL dinamico:

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 

Questa approssima una funzione temporanea globale, se una cosa del genere esistesse. È ancora visibile agli altri utenti. È possibile aggiungere lo SPID @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

4

So che potrei essere criticato per aver suggerito SQL dinamico, ma a volte è una buona soluzione. Assicurati di aver compreso le implicazioni sulla sicurezza prima di considerare questo.

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' 
1

Il sotto è quello che ho usato io il passato per realizzare la necessità di uno scalare UDF in MS SQL:

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 

Questo approccio, che utilizza una variabile globale per la procedura consente di effettuare uso della funzione non solo nei tuoi script, ma anche nelle tue esigenze di SQL dinamico.

Problemi correlati