2012-09-26 12 views
7

Esiste un modo per creare una funzione definita dall'utente CLR per SQL Server che restituisce più valori senza utilizzare la sintassi della funzione di valore di tabella? Ad esempio, supponiamo di voler eseguire una conversione di coordinate come:UDF CLR di SQL Server con parametri di uscita - È possibile?

[SqlFunction()] 
public void ConvertCoordinates(SqlDouble x, SqlDouble y, SqlDouble z, out SqlDouble r, out SqlDouble t, out SqlDouble p) 
{ 
    r = new SqlDouble(Math.Sqrt((x.Value*x.Value)+(y.Value*y.Value)+(z.Value*z.Value))); 
    t = new SqlDouble(Math.Acos(r.Value/z.Value)); 
    p = new SqlDouble(Math.Atan(y.Value/x.Value)); 
} 

È possibile? Una funzione valutata a livello di tabella in questo caso sembra inappropriata perché il calcolo non genererà mai più di una riga di output. Usando la sintassi della funzione con valori scalari, dovrei scrivere tre diverse funzioni per eseguire il calcolo e chiamarle separatamente. Dato il mio caso d'uso reale, questo è altamente impraticabile.

Mi rendo conto che la logica di cui sopra può essere realizzata utilizzando puro T-SQL; il mio caso d'uso reale è più complesso ma comporterebbe comunque una sola riga con più valori di uscita interdipendenti.

Quindi, linea di fondo, è fattibile? Non penso che lo sia, ma si può sperare. Se per caso è fattibile, allora come apparirebbe il T-SQL che chiama tale funzione?

+1

UDF (sia scalare che tabulare, T-SQL o CLR) non possono avere parametri out. Se potessero, dovresti inventare una nuova sintassi per consentire a uno di essere chiamato nella clausola 'SELECT', se tu volessi consumare queste uscite. E non vedo perché una funzione valutata a livello di tabella che restituisce una singola riga ti debba sembrare strana. –

+1

@Damien Questa era semplicemente una questione se fosse possibile o meno.La mia lettura e sperimentazione avevano indicato che probabilmente non lo era (come ho anche affermato), ma poiché sono nuovo all'integrazione CLR, volevo chiedere. Le TVF non sembrano "strane per me" quando più di una riga è una possibilità. L'esempio SEMPRE restituisce una singola riga, tuttavia i valori di ritorno correlati sono significativi solo come un insieme. Nel mio caso di utilizzo reale sto eseguendo un calcolo simile, ma più grande per milioni di righe, quindi un TVF sembra inefficiente solo se i parametri out erano una possibilità. Un semplice "no" sarebbe stato sufficiente. – bporter

+0

@bporter - ovviamente un TVF sarebbe l'opzione migliore - lo dici tu stesso, loro "non sembrano strani quando più di 1 riga è una possibilità" e poi dici che hai milioni di righe. Ergo a (S) TVF è la risposta! Sarà molto più efficiente di iterare su ogni riga come una dichiarazione foreach imperativa. – gbjbaanb

risposta

3

Dal momento che hai già preso il grande passo CLR, è possibile creare il proprio tipo CLR con cui è possibile fare ogni sorta di cose pazze. Come esempio pratico, i tipi spaziali nativi sono implementati in questo modo, come lo è HierarchyID. Una volta definito il tuo tipo, puoi far sì che la funzione lo restituisca. Se si ottengono singoli componenti (se posso presumere nel tuo caso raggio, theta e phi), creare metodi sul tipo che restituiscono tali.

+0

Grazie per il suggerimento. Gli UDT renderebbero tutto molto più semplice e li ho esaminati. L'unica preoccupazione che avevo era che dovevo registrare l'assemblea con ogni database. Nel mio caso, sto estraendo dati da centinaia di database accumulati negli ultimi 10 anni circa. Le UDF sembravano più semplici perché potevo inserirle in un database e chiamarle dagli altri database per eseguire calcoli. C'è un modo che sai di rendere gli UDT disponibili su tutti i database simili ai tipi spaziali (senza registrare l'assembly con ogni database)? – bporter

+0

Posso pensare ad un paio di approcci. Il primo è se lo registrate una sola volta in un db e fate tutta la vostra raccolta di dati in quel contesto di db. L'altro sarebbe dispiegarlo ovunque. Dato che è T-SQL e probabilmente hai già un modo per eseguire il codice contro ogni db, questo non dovrebbe essere un problema. Tenere presente che è possibile distribuire gli assembly attraverso un flusso di bit direttamente nello script piuttosto che dover distribuire la DLL ovunque e fare riferimento a ciò. –

-1

Ammetto che non ho provato, ma immagino che il T-SQL vorrebbe,

DECLARE @X FLOAT(53), 
     @Y FLOAT(53), 
     @Z FLOAT(53), 
     @R FLOAT(53), 
     @T FLOAT(53), 
     @P FLOAT(53) 

EXEC ConvertCoordinates 
     @X = 0, 
     @Y = 0, 
     @Z = 0, 
     @R = @R OUTPUT, 
     @T = @T OUTPUT 
     @P = @P OUTPUT 
1

Questa è una domanda precedente e l'ho trovata mentre cercavo una risposta a una domanda molto simile.

Le funzioni SQL consentono un valore di ritorno ma non consentono l'utilizzo di un parametro di uscita.

Procedure SQL CONSENTONO parametri di uscita (ma non un valore di ritorno)

Ho trovato questo da MSDN Esempio qui:

http://technet.microsoft.com/en-us/library/ms131092.aspx

[Microsoft.SqlServer.Server.SqlProcedure] 
public static void PriceSum(out SqlInt32 value) 
{ … } 

e

CREATE PROCEDURE PriceSum (@sum int OUTPUT) 
AS EXTERNAL NAME TestStoredProc.StoredProcedures.PriceSum 

Quando sono passato dal provare a registrare una funzione in una procedura uro tutto ha funzionato. Va sottolineato che una funzione può avere un valore di ritorno ma una procedura memorizzata non può. Nel mio caso stavo restituendo un valore di stringa e avevo parametri di output per alcune informazioni dettagliate opzionali come i codici di stato, ecc. Tutto ciò che ho fatto è stato cambiare il mio metodo per essere un vuoto e passato il valore di stringa come parametro di output.

Il metodo è comunque un void e non ha alcun valore di ritorno e in quanto tale è un candidato perfetto per l'utilizzo di una stored procedure anziché di una funzione.

Problemi correlati