Posso creare una funzione monouso in uno script o in una stored procedure?


109

In SQL Server 2005 esiste il concetto di una funzione monouso o locale dichiarata all'interno di uno script SQL o di una stored procedure? Vorrei astrarre un po 'di complessità in uno script che sto scrivendo, ma richiederebbe essere in grado di dichiarare una funzione.

Solo curioso.


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

stai generando una funzione dinamicamente in modo che sia diversa ogni volta? se la tua funzione è sempre la stessa lasciala nel database
KM.

1
Stavo cercando di farlo come un modo per rendere la query più leggibile. L'idea di creare query enormi rende difficile la manutenzione.
Jp_

Risposte:


65

Puoi chiamare CREATE Functionvicino all'inizio del tuo script e DROP Functionverso la fine.


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

6
Puoi fare un controllo SE ESISTE prima di ogni esecuzione ed eliminare se viene trovato qualcosa.
Adrian Godong,

7
@chocojosh, dovrebbe andare bene se lo includi in una transazione. La funzione non dovrebbe essere nel database se la transazione è esplosiva.
Jeff LaFay

12
@ JoelCoehoorn: questo richiede ancora i privilegi di scrittura.
user2284570

2
Nota che questo non funzionerà all'interno di una funzione: le funzioni temporanee all'interno delle funzioni non sono consentite. Vedi: technet.microsoft.com/en-us/library/ms191320.aspx#Restrictions
Daniel Neel

95

Puoi creare stored procedure temporanee come:

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

in uno script SQL, ma non nelle funzioni. Tuttavia, potresti fare in modo che il proc memorizzi il risultato in una tabella temporanea, quindi utilizza tali informazioni più avanti nello script.


7
Questa dovrebbe essere la risposta. Questo è veramente monouso se solo con ambito di connessione temporaneo (singolo #) e ha il vantaggio di aggirare le restrizioni dell'utente sql.
Todd

Come si usa allora? Non è un errore di battitura nel nome della procedura utilizzato nell'espressione select into?
jgomo3

Sono in grado di ottenere risultati dalla procedura memorizzata di esempio quando rimuovo la BEGINparola chiave e la sostituisco ENDcon GO.
Joseph Dykstra

L'OP stava chiedendo una FUNZIONE temporanea e almeno SQL Server 2012 non consentirà la sintassi # per le funzioni. Solo procedure.
Erk

Questa non è una funzione all'interno di uno script e potrebbe comunque richiedere autorizzazioni. Per evitare segmenti ripetitivi, l'unica opzione disponibile in SQL è l'istruzione WITH.
alex.peter

25

Le espressioni di tabella comuni consentono di definire quelle che 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.


5
Questo dovrebbe essere accettato come risposta corretta. La risposta accettata non è thread-safe.
kalyan

11
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 interessa la sicurezza dei thread e le CTE non funzioneranno per me.
solipsicle

16
Penso che questa risposta, e le affermazioni che sia la risposta corretta, perdano il fatto che la domanda cerchi una FUNZIONE temporanea, non una TABELLA temporanea. A meno che non mi manchi qualcosa (non raro), i CTE sono paragonabili alle tabelle temporanee.
JD Long

8
Una funzione può accettare argomenti mentre un CTE no.
Răzvan Flavius ​​Panda

4
Esistono molte differenze tra un CTE e una stored procedure temporanea (che è la risposta corretta qui IMO). Per i principianti, le CTE esistono solo per una singola istruzione, mentre le variabili temporanee possono essere utilizzate in uno script. Altre differenze includono: (1) le CTE non possono ospitare la stessa logica di cui può disporre un SP, (2) le CTE non possono accettare variabili. Un CTE è solo zucchero sintattico che consente di creare più facilmente espressioni di tabella nidificate da utilizzare in un'istruzione. Anche allora possono essere pericolosi dal punto di vista delle prestazioni se non sei a conoscenza degli avvertimenti.
sbilenco

12

So che potrei essere criticato per aver suggerito SQL dinamico, ma a volte è una buona soluzione. Assicurati solo di comprendere le implicazioni sulla sicurezza prima di prenderlo in considerazione.

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'

4

Negli script hai più opzioni e una migliore possibilità di decomposizione razionale. Guarda in modalità SQLCMD (Menu Query -> modalità SQLCMD), in particolare i comandi: setvar e: r.

All'interno di una procedura memorizzata le tue opzioni sono molto limitate. Non è possibile creare definire una funzione direttamente con il corpo di una procedura. Il meglio che puoi fare è qualcosa del genere, 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

Ciò si avvicina a una funzione temporanea globale, se una cosa del genere esistesse. È ancora visibile ad altri utenti. È possibile aggiungere @@ SPID della connessione per univocare il nome, ma ciò richiederebbe anche il resto della procedura per utilizzare SQL dinamico.


3

Di seguito è riportato ciò che ho usato in passato per soddisfare la necessità di una UDF scalare 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 utilizzare la funzione non solo negli script, ma anche nelle esigenze di Dynamic SQL.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.