Jag har en lagrad proc spGetSites som returnerar tre kolumner för SiteName, SiteId och UnitCount. Den lagrade proc fungerar helt bra. Jag försöker lagra resultaten av den lagrade proc till en temp-tabell @Site för att använda för min rapport med nedanstående syntax. Den här gången fick jag ett felmeddelande: ”INSERT EXEC-uttalande kan inte kapslas”
Kan jag inte använda INSERT- och EXEC-uttalanden samtidigt?
DECLARE @Site TABLE (SiteName VARCHAR(100), SiteId INT, UnitCount INT) INSERT INTO @Site EXEC spGetSites @SiteId = 0
Kommentarer
- Du borde , dbfiddle.uk/… Lägg till den lagrade proceduren i frågan och märka din SQL Server-version.
Svar
Om du tittar på koden för din spGetSites
förfarande, någonstans i det förfarandet är en annan INSERT...EXEC
. Det kan vara direkt i det förfarandet, eller kapslat i tarmarna av någon annan procedur som det kallar.
I slutändan, om en lagrad procedur använder INSERT...EXEC
, om du försöker ringa den lagrade proceduren i samband med en annan INSERT...EXEC
får du det fel du är seende .
Hur fixar du det?
-
Du kan helt enkelt ta det inre
INSERT...EXEC
och infoga koden till detta enkel lagrad procedur. Men jag misstänker att andra procedurer kan finnas där av en anledning: dvs att hålla din kod TORR. -
Eftersom det här är en
Get
procedur, förhoppningsvis finns det ingen datahantering någonstans i samtalsstacken. Du kan konvertera barnproceduren till en tabellvärderad funktion. Detta gör att du kan konvertera den inreINSERT...EXEC
till enINSERT...SELECT
och lösa problemet. -
Använd temp-tabeller som omfattas av den yttre proceduren för att skicka data mellan procedurerna. Denna lösning blir komplicerat, så det är inte min favorit, och jag avskräcker i allmänhet detta mönster när det finns ett bättre alternativ – men för fullständighetens skull tar jag det här. I grund och botten, om du skapar din #temp-tabell utanför
spGetSites
kan du använda den ispGetSites
(utan att skapa den där inne), och tabellen med inlagda data kommer att överleva procedurutförandet och fortsätta att arbeta.
Jag gillar inte alternativ 3 eftersom det är ett kodningsmönster som är tillräckligt komplext för att säkerställa att någon förstör det i framtiden, såvida inte alla är ombord och bekanta med kodningen mönster: * spGetSites
misslyckas om du inte skapar tabellen först. Alla som ringer måste komma ihåg att skapa tabellen exakt samma först. * spGetSites
kan inte anta att tabellen är tom. Den kan ha befintlig data från det yttre samtalet (eller en tidigare körning från samma uppringare) * Felsökning och felsökning (och till och med få en frågeplan) för spGetSites
är mer komplex på grund av tabellskapande förvirring.
Vad skulle jag göra?
Utan att veta hur komplex den koden ligger bakom spGetSites
, jag skulle se till att skapa en inbyggd TVF som ersätter den inre INSERT...EXEC
med INSERT...SELECT
eller eventuellt hela spGetSites
kan förenklas / skrivas om för att göra det fristående utan INSERT...EXEC