Tengo un proc spGetSites almacenado que devuelve tres columnas para SiteName, SiteId y UnitCount. El proceso almacenado funciona perfectamente bien. Estoy tratando de almacenar los resultados del proceso almacenado en una tabla temporal @Site para usar en mi informe con la siguiente sintaxis. Esta vez recibí un mensaje de error: «La instrucción INSERT EXEC no se puede anidar»
¿No puedo usar la instrucción INSERT y EXEC al mismo tiempo?
DECLARE @Site TABLE (SiteName VARCHAR(100), SiteId INT, UnitCount INT) INSERT INTO @Site EXEC spGetSites @SiteId = 0
Comentarios
- Debería , dbfiddle.uk/… Agregue su procedimiento almacenado a la pregunta y etiquete su versión de SQL Server.
Respuesta
Si miras el código de tu spGetSites
procedimiento, en algún lugar de ese procedimiento hay otro INSERT...EXEC
. Puede estar directamente en ese procedimiento, o anidado en las entrañas de algún otro procedimiento al que llama.
En última instancia, si un procedimiento almacenado usa INSERT...EXEC
, entonces si intenta llamar a ese procedimiento almacenado en el contexto de otro INSERT...EXEC
obtendrá el error que está vidente .
¿Cómo se soluciona?
-
Simplemente puede tomar el
INSERT...EXEC
interno e insertar el código en este procedimiento almacenado único. Sin embargo, sospecho que puede haber otro procedimiento por una razón: es decir, para mantener su código SECO. -
Dado que este es un
Get
procedimiento, con suerte no hay manipulación de datos en ninguna parte de la pila de llamadas. Puede convertir el procedimiento hijo en una función con valores de tabla. Esto le permitiría convertir eseINSERT...EXEC
interno en unINSERT...SELECT
y resuelva este problema. -
Use tablas temporales dentro del ámbito del procedimiento externo para pasar datos entre procedimientos. Esta solución obtiene complicado, por lo que no es mi favorito, y generalmente desaconsejo este patrón cuando hay una mejor opción, pero en aras de la integridad, lo incluiré aquí. Básicamente, si crea su tabla #temp fuera de
spGetSites
, puede usarla dentro despGetSites
(sin crearla allí dentro), y la tabla con datos insertados sobrevivirá a la ejecución del procedimiento y continuará funcionando.
No me gusta la opción 3 porque es un patrón de codificación lo suficientemente complejo como para asegurar que alguien lo arruine en el futuro, a menos que todos estén a bordo y familiarizados con la codificación patrón: * spGetSites
fallará a menos que cree la tabla primero. Todas las personas que llaman deben recordar crear la tabla exactamente igual primero. * spGetSites
no puede «asumir que la tabla está vacía. Podría tener datos existentes de la llamada externa (o una ejecución previa del mismo llamador) * Solución de problemas y depuración (e incluso obtener un plan de consulta) para spGetSites
es más complejo debido a la confusión de creación de la tabla.
¿Qué haría?
Sin saber qué tan complejo es el código está detrás de spGetSites
, buscaría crear un TVF en línea que reemplace el INSERT...EXEC
interno con INSERT...SELECT
o posiblemente todo spGetSites
podría simplificarse / reescribirse para hacerlo autónomo sin INSERT...EXEC