2010-07-16 33 views
57

Tengo un procedimiento almacenado que tiene una serie de parámetros de entrada y salida porque está insertando valores en varias tablas. En algunos casos, el proceso almacenado solo se inserta en una sola tabla (dependiendo de los parámetros de entrada). Aquí hay un escenario simulado para ilustrar.¿Puedo tener un parámetro OUTPUT opcional en un procedimiento almacenado?

Tablas/Objetos de datos:

persona

Id 
Name 
Address 

Nombre

Id 
FirstName 
LastName 

Dirección

Id 
Country 
City 

Supongamos que tengo un procedimiento almacenado que inserta a una persona. Si la dirección no existe, no la agregaré a la tabla Address en la base de datos.

Por lo tanto, cuando genero el código para llamar al procedimiento almacenado, no quiero molestarme en agregar el parámetro Address. Para los parámetros INPUT, esto está bien porque SQL Server me permite suministrar valores predeterminados. Pero para el parámetro OUTPUT qué es lo que se puede hacer en el procedimiento almacenado para que sea opcional, así que no reciben un error ...

procedimiento o función 'Person_InsertPerson' espera el parámetro '@AddressId', que se no incluido.

+0

Lo que se ve su código como? Es decir, en algún lugar estás ramificando sobre si existe una dirección. Sospecho que mi pregunta, una vez que vea esa rama, sería: "¿Por qué no llamar a sproc con' NULL' en lo que pase para '@ AddressId' cuando una dirección no existe, * sin * usar una rama?" – ruffin

Respuesta

90

Se pueden asignar valores predeterminados tanto a los parámetros de entrada como a los de salida.En este ejemplo:

CREATE PROCEDURE MyTest 
    @Data1 int 
,@Data2 int = 0 
,@Data3 int = null output 

AS 

PRINT @Data1 
PRINT @Data2 
PRINT isnull(@Data3, -1) 

SET @Data3 = @Data3 + 1 

RETURN 0 

se requiere el primer parametro, y el segundo y tercero son opcionales - si no se establece por la rutina de llamada, que se asignarán los valores por defecto. Trate de jugar con él y la siguiente rutina de llamada de prueba en SSMS usando diferentes valores y configuraciones para ver cómo funciona todo junto.

DECLARE @Output int 

SET @Output = 3 

EXECUTE MyTest 
    @Data1 = 1 
,@Data2 = 2 
,@Data3 = @Output output 

PRINT '---------' 
PRINT @Output 
+2

¡Gracias! Me preguntaba por qué no podía usar '@var INT OUTPUT = NULL' - la sintaxis es confusa. – trojjer

+0

en realidad no invoca el valor predeterminado (configure @output) los valores predeterminados solo se activan cuando NO pasa algo, consulte mi respuesta para obtener un tratamiento completo. –

1

Puesto que usted está ejecutando un procedimiento almacenado y no una instrucción SQL, usted tiene que establecer el tipo de mando de su comando SQL a procedimiento almacenado:

cmd.CommandType = CommandType.StoredProcedure; 

Tomado de here.

Además, una vez que obtiene ese error eliminado, puede utilizar la función nvl() de SQL en su procedimiento para especificar lo que desea mostrar cuando se encuentra un valor NULL.

Disculpa por no haber abordado correctamente la pregunta ... no te he entendido bien. Aquí hay un ejemplo de nvl, que creo que podría abordarlo un poco mejor.

select NVL(supplier_city, 'n/a') 
from suppliers; 

La sentencia SQL anterior volvería 'n/a' si el campo supplier_city contenía un valor nulo. De lo contrario, devolvería el valor supplier_city.

+0

Eso no responde la pregunta. Estoy usando el archivo db.GetStoredProcCommand de Enterprise Library, que hará eso por mí. He llamado a muchos procesos almacenados de esta manera y funcionan bastante bien. por ej. Código para llamar al StoredProc usando (DbCommand insertPersonCommand = db.GetStoredProcCommand ("Person_InsertPerson")) { this.AppendInsertPersonParameters (db, insertPersonCommand); db.ExecuteNonQuery (insertPersonCommand, dbTransaction); – Justin

+0

Lo siento amigo. Lo edité para ser un poco más relevante. – rownage

4

Parece que sólo puede agregar un valor predeterminado para el parámetro OUTPUT tales como:

@AddressId int = -1 Output 

parece que es pobre en términos de facilidad de lectura desde AddressId está destinada estrictamente como una variable OUTPUT. Pero funciona. Por favor, avíseme si tiene una mejor solución.

+0

esto tiene dificultades, vea mi respuesta para un tratamiento completo. –

1

la adición a lo que dijo Felipe:

tuve un procedimiento almacenado en mi base de datos del servidor SQL que se parecía a lo siguiente:

dbo.<storedProcedure> 
(@current_user char(8) = NULL, 
@current_phase char(3) OUTPUT) 

Y yo estaba llamando desde mi .net código como el siguiente:

DataTable dt = SqlClient.ExecuteDataTable(<connectionString>, <storedProcedure>); 

que estaba recibiendo un System.Data.SqlClient.SqlException: Procedimiento o funcio n espera el parámetro '@current_phase', que no se suministró.

También estoy usando esta función en otro lugar en mi programa y pasando un parámetro y manejo de la salida. Para no tener que modificar la llamada actual que estaba haciendo, simplemente cambié el procedimiento almacenado para hacer que el parámetro de salida también fuera opcional.

Por lo tanto, ahora se ve como la siguiente: parámetros

dbo.<storedProcedure> 
(@current_user char(8) = NULL, 
@current_phase char(3) = NULL OUTPUT) 
7

de salida y los valores por defecto no funcionan bien juntos! Esto es de SQL 10.50.1617 (2008 R2). No se deje engañar creyendo que esta construcción mágicamente hace un SET a ese valor en su nombre (¡como lo hizo mi compañero de trabajo)!

Este "juguete" SP interroga al valor del parámetro OUTPUT, si es el valor predeterminado o NULL.

CREATE PROCEDURE [dbo].[omgwtf] (@Qty INT, @QtyRetrieved INT = 0 OUTPUT) 
AS 
IF @QtyRetrieved = 0 
BEGIN 
    print 'yay its zero' 
END 
IF @QtyRetrieved is null 
BEGIN 
    print 'wtf its NULL' 
END 
RETURN 

Si envía un valor no inicializado (es decir NULL) para la OUTPUT, que realmente tiene NULL dentro de la SP, y no 0. Tiene sentido, algo pasó para ese parámetro.

declare @QR int 
exec [dbo].[omgwtf] 1, @QR output 
print '@QR=' + coalesce(convert(varchar, @QR),'NULL') 

salida es:

wtf its NULL 
@QR=NULL 

Si añadimos una explícita SET de la persona que llama se obtiene:

declare @QR int 
set @QR = 999 
exec [dbo].[omgwtf] 1, @QR output 
print '@QR=' + coalesce(convert(varchar, @QR),'NULL') 

y la salida (sorprendente):

@QR=999 

De nuevo, tiene sentido, se pasa un parámetro, y SP no tomó acción explícita a SET un valor.

Añadir un SET del parámetro OUTPUT en el SP (como se supone que hacer), pero no establecen nada de la persona que llama:

ALTER PROCEDURE [dbo].[omgwtf] (@Qty INT, @QtyRetrieved INT = 0 OUTPUT) 
AS 
IF @QtyRetrieved = 0 
BEGIN 
    print 'yay its zero' 
END 
IF @QtyRetrieved is null 
BEGIN 
    print 'wtf its NULL' 
END 
SET @QtyRetrieved = @Qty 
RETURN 

Ahora cuando es ejecutado:

declare @QR int 
exec [dbo].[omgwtf] 1234, @QR output 
print '@QR=' + coalesce(convert(varchar, @QR),'NULL') 

la salida es:

wtf its NULL 
@QR=1234 

Este es el comportamiento "estándar" para OUTPUT gestión de parámetros en SP.

Ahora, para el giro parcela: La única manera de obtener el valor por defecto para "activar", es no pasa el parámetro OUTPUT en absoluto, que en mi humilde opinión no tiene mucho sentido: ya que está configurado como un OUTPUT parámetro, eso significaría devolver algo "importante" que debería ser recolectado.

declare @QR int 
exec [dbo].[omgwtf] 1 
print '@QR=' + coalesce(convert(varchar, @QR),'NULL') 

da este resultado:

yay its zero 
@QR=NULL 

Pero esto no logra captar la salida SP, presumiblemente con el fin de que la SP para empezar.

mi humilde opinión esta combinación característica es una construcción dudosa que yo consideraría un código olor (uff !!)

+0

¿Cuál es la ventaja, la brevedad (incluida la reutilización de variables en el código que podría llamar a esto y a otros sprocs), al uso de los parámetros 'OUTPUT' para la entrada? ¿Por qué no pasar esos valores de entrada como parámetros "regulares"? – ruffin

+1

@ruffin no hay ventaja; Los parámetros opcionales de SALIDA no funcionan como todo el mundo espera, y es por eso que construí esta respuesta. –

+0

+1. Creo que simplemente agregaría que eso significa pasar valores a través de parámetros 'OUTPUT' c/sh/sería considerado una mala idea por dos razones: 1. olor ideológico/código, y 2. razones prácticas del comportamiento que has tenido encontrado aquí. ¯ \\ _ (ツ) _/¯ – ruffin

Cuestiones relacionadas