Tengo tres procedimientos almacenados Sp1
, Sp2
y Sp3
.
El primero ( Sp1
) ejecutará el segundo ( Sp2
) y guardará los datos devueltos en @tempTB1
y el segundo ejecutará el tercero ( Sp3
) y guardará los datos en @tempTB2
.
Si ejecuto el Sp2
, funcionará y me devolverá todos mis datos del Sp3
, pero el problema está en el Sp1
, cuando lo ejecute, mostrará este error:
La instrucción INSERT EXEC no se puede anidar
Intenté cambiar el lugar de execute Sp2
y me muestra otro error:
No se puede utilizar la instrucción ROLLBACK dentro de una instrucción INSERT-EXEC.
sp_help_jobactivity
).Esta es la única forma "simple" de hacer esto en SQL Server sin una función creada enrevesada gigante o una llamada de cadena SQL ejecutada, las cuales son soluciones terribles:
EJEMPLO:
Nota : DEBE usar 'set fmtonly off', Y NO PUEDE agregar sql dinámico a esto dentro de la llamada openrowset, ya sea para la cadena que contiene los parámetros de su procedimiento almacenado o para el nombre de la tabla. Es por eso que debe usar una tabla temporal en lugar de variables de tabla, lo que hubiera sido mejor, ya que supera a la tabla temporal en la mayoría de los casos.
fuente
OK, alentado por jimhark aquí hay un ejemplo del antiguo enfoque de tabla hash única: -
fuente
Mi solución para este problema siempre ha sido utilizar el principio de que las tablas temporales de hash único están dentro del alcance de cualquier proceso llamado. Entonces, tengo un interruptor de opción en los parámetros de proceso (predeterminado en apagado). Si está activado, el proceso llamado insertará los resultados en la tabla temporal creada en el proceso de llamada. Creo que en el pasado he dado un paso más y puse algo de código en el proceso llamado para verificar si la tabla hash única existe en el alcance, si es así, inserte el código; de lo contrario, devuelva el conjunto de resultados. Parece funcionar bien: la mejor manera de pasar grandes conjuntos de datos entre procesos.
fuente
Este truco me funciona.
No tiene este problema en el servidor remoto, porque en el servidor remoto, el último comando de inserción espera a que se ejecute el resultado del comando anterior. No es el caso en el mismo servidor.
Aproveche esa situación para obtener una solución.
Si tiene los permisos adecuados para crear un servidor vinculado, hágalo. Cree el mismo servidor que el servidor vinculado.
ahora su comando Sql en el SP1 es
Créame, funciona incluso si tiene una inserción dinámica en SP2
fuente
Encontré que una solución es convertir uno de los productos en una función con valores de tabla. Me doy cuenta de que no siempre es posible y presenta sus propias limitaciones. Sin embargo, siempre he podido encontrar al menos uno de los procedimientos un buen candidato para esto. Me gusta esta solución, porque no introduce ningún "truco" en la solución.
fuente
Encontré este problema al intentar importar los resultados de un proceso almacenado en una tabla temporal, y ese proceso almacenado se insertó en una tabla temporal como parte de su propia operación. El problema es que SQL Server no permite que el mismo proceso escriba en dos tablas temporales diferentes al mismo tiempo.
La respuesta OPENROWSET aceptada funciona bien, pero necesitaba evitar el uso de SQL dinámico o un proveedor OLE externo en mi proceso, así que tomé una ruta diferente.
Una solución fácil que encontré fue cambiar la tabla temporal en mi procedimiento almacenado a una variable de tabla. Funciona exactamente igual que con una tabla temporal, pero ya no entra en conflicto con mi otro inserto de tabla temporal.
Solo para encabezar el comentario, sé que algunos de ustedes están a punto de escribir, advirtiéndome de las variables de tabla como asesinos del rendimiento ... Todo lo que puedo decirles es que en 2020 vale la pena no tener miedo a las variables de tabla. Si esto fue en 2008 y mi base de datos estaba alojada en un servidor con 16 GB de RAM y funcionando con discos duros de 5400 RPM, podría estar de acuerdo con usted. Pero es 2020 y tengo una matriz SSD como mi almacenamiento principal y cientos de gigas de RAM. Podría cargar la base de datos de toda mi empresa en una variable de tabla y aún tener suficiente RAM de sobra.
¡Las variables de tabla están de vuelta en el menú!
fuente
Tuve el mismo problema y preocupación por el código duplicado en dos o más sprocs. Terminé agregando un atributo adicional para "modo". Esto permitió que existiera un código común dentro de un sproc y el flujo dirigido por modo y el conjunto de resultados del sproc.
fuente
¿Qué tal simplemente almacenar la salida en la tabla estática? Me gusta
no es lo ideal, pero es tan simple y no es necesario volver a escribir todo.
ACTUALIZACIÓN : la solución anterior no funciona bien con consultas paralelas (acceso asíncrono y multiusuario), por lo tanto, ahora estoy usando tablas temporales
spGetData
contenido de procedimiento almacenado anidadofuente
Declare una variable de cursor de salida al sp interno:
Luego, declare un cursor c a la selección que desea devolver. Luego abre el cursor. Luego establezca la referencia:
NO cierre ni reasigne.
Ahora llame al sp interno desde el externo proporcionando un parámetro de cursor como:
Una vez que se ejecuta el sp interno,
@cOUT
está listo para recuperar. Bucle y luego cierre y desasigne.fuente
Si puede utilizar otras tecnologías asociadas, como C #, le sugiero que utilice el comando SQL integrado con el parámetro Transaction.
Creé una aplicación de consola simple que demuestra esta capacidad que se puede encontrar aquí: https://github.com/hecked12/SQL-Transaction-Using-C-Sharp
En resumen, C # le permite superar esta limitación en la que puede inspeccionar la salida de cada procedimiento almacenado y usar esa salida como quiera, por ejemplo, puede alimentarlo a otro procedimiento almacenado. Si el resultado es correcto, puede confirmar la transacción; de lo contrario, puede revertir los cambios mediante la reversión.
fuente
En SQL Server 2008 R2, tuve una falta de coincidencia en las columnas de la tabla que causó el error de reversión. Desapareció cuando arreglé mi variable de tabla sqlcmd poblada por la instrucción insert-exec para que coincida con la devuelta por el proceso almacenado. Faltaba el código_org. En un archivo cmd de Windows, carga el resultado del procedimiento almacenado y lo selecciona.
fuente