2012-09-26 26 views
7

¿Existe alguna manera de crear una función CLR definida por el usuario para SQL Server que devuelva múltiples valores sin usar la sintaxis de la función de valores de tabla? Por ejemplo, digamos que desea realizar una conversión de coordenadas, tales como:SQL Server CLR UDF con parámetros de salida: ¿es posible?

[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)); 
} 

Es esto posible? Una función con valores de tabla en este caso parece inapropiada porque el cálculo nunca arrojará más de una fila de salida. Usando la sintaxis de la función de valor escalar, tendría que escribir tres funciones diferentes para realizar el cálculo y llamar cada uno por separado. Dado mi caso de uso real, esto es muy poco práctico.

Me doy cuenta de que la lógica anterior se puede lograr usando T-SQL puro; mi caso de uso real es más complejo, pero aún así solo resultaría en una sola fila con múltiples valores de salida interdependientes.

Entonces, en conclusión, ¿es factible? No creo que sea, pero uno puede esperar. Si por casualidad es factible, ¿cómo se vería el T-SQL que llama a tal función?

+1

Las UDF (ya sean escalares o tabulares, T-SQL o CLR) no pueden tener parámetros de salida. Si pudieran, tendrías que inventar una nueva sintaxis para permitir que se llame a uno en la cláusula 'SELECT', si querías consumir estas salidas. Y no veo por qué una función con valores de tabla que devuelva una sola fila le parezca extraña. –

+1

@Damien Esto era simplemente una cuestión de si es posible o no.Mi propia lectura y experimentación indicaron que probablemente no era (como también dije), pero como soy nuevo en la integración de CLR, quería preguntar. Las TVF no me parecen "extrañas" cuando hay más de una fila disponible. El ejemplo SIEMPRE devuelve una sola fila, pero los valores de retorno interrelacionados solo son significativos como un conjunto. En mi caso de uso real estoy realizando un cálculo similar pero mayor para millones de filas, por lo que un TVF simplemente parece ineficaz si los parámetros fueran una posibilidad. Un simple 'no' hubiera sido suficiente. – bporter

+0

@bporter - obviamente, una TVF sería la mejor opción - usted mismo lo dice, "no parece extraño cuando hay más de 1 fila es una posibilidad" y luego dice que tiene millones de filas. Ergo a (S) TVF es la respuesta! Va a ser mucho más eficiente que iterar sobre cada fila como una declaración imperativa de foreach. – gbjbaanb

Respuesta

3

Como ya ha dado el paso CLR, puede crear su propio tipo CLR con el que puede hacer todo tipo de cosas locas Como ejemplo práctico, los tipos espaciales nativos se implementan de esta manera, al igual que HierarchyID. Una vez que haya definido su propio tipo, puede hacer que su función lo devuelva. Si se trata de componentes individuales (si puedo suponer en el radio de su caso, theta y phi), cree métodos en el tipo que lo devuelva.

+0

Gracias por la sugerencia. Los UDT harían esto mucho más simple, y los investigué. La única preocupación que tenía era que tenía que registrar el ensamblaje con cada base de datos. En mi caso, estoy extrayendo datos de cientos de bases de datos acumuladas en los últimos 10 años más o menos. Las UDF parecían más simples porque podía ubicarlas en una base de datos y llamarlas desde otras bases de datos para realizar cálculos. ¿Hay alguna forma que conozcas para hacer que los UDT estén disponibles en todas las bases de datos de forma similar a los tipos espaciales (sin registrar el ensamblado con cada base de datos)? – bporter

+0

Puedo pensar en un par de enfoques. El primero es si solo lo registras una vez en un db y haces toda tu recopilación de datos en el contexto de ese db. El otro sería desplegarlo en todas partes. Dado que se trata de T-SQL y, presumiblemente, usted ya tiene una forma de ejecutar código en cada db, esto no debería ser un problema. Tenga en cuenta que puede implementar ensamblajes a través de un flujo de bits directamente en el script en lugar de tener que implementar el archivo DLL en todas partes y hacer referencia a eso. –

-1

Admito que no lo he probado, pero me imagino que el T-SQL quisiera,

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

Esta es una pregunta anterior y la encontré al buscar una respuesta a una pregunta muy similar.

SQL Las funciones permiten un valor de retorno pero no permiten el uso de un parámetro de salida.

procedimientos de SQL permiten parámetros de salida (pero no un valor de retorno)

yo encontramos este del Ejemplo MSDN aquí:

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

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

y

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

Cuando cambié de intentar registrar una función a un procedimiento si todo salió bien. Se debe señalar que una función puede tener un valor de retorno, pero un procedimiento almacenado no puede. En mi caso, estaba devolviendo un valor de cadena y tenía parámetros de salida para alguna información detallada opcional como códigos de estado, etc. Todo lo que hice fue cambiar mi método para que fuera un vacío y pasé el valor de la cadena de nuevo como un parámetro de salida.

Su método es un vacío de todos modos y no tiene ningún valor de retorno y como tal es un candidato perfecto para utilizar un procedimiento almacenado en lugar de una función.

Cuestiones relacionadas