2013-11-04 6 views
8

SQL Server mi permette di inserire il set di risultati restituito di una stored procedure come:INSERT INTO con exec con esito più set

DECLARE @T TABLE (
    ID int, 
    Name varchar(255), 
    Amount money) 

INSERT INTO @T 
exec dbo.pVendorBalance 

Questo funziona fino a quando la stored procedure restituisce solo 1 risultato set.

C'è un modo per farlo funzionare se la stored procedure restituisce più set di risultati?

E.g.

DECLARE @T1 (...) 
DECLARE @T2 (...) 

INSERT INTO @T1 THEN INTO @T2 
exec dbo.pVendorBalance 
+0

Hai mai trovare un modo per fare questo? –

risposta

0

In realtà le stored procedure possono restituire più set di risultati, o nessun set di risultati, è piuttosto arbitrario. Per questo motivo, non conosco alcun modo per navigare quei risultati da altri codici SQL che chiamano una stored procedure.

Tuttavia, è possibile utilizzare il set di risultati restituito da una funzione definita dall'utente con valori di tabella. È proprio come una normale UDF, ma invece di restituire un valore scalare si restituisce un risultato di una query. Quindi puoi usare quella UDF come qualsiasi altra tabella.

INSERT INTO @T SELECT * FROM dbp.pVendorBalanceUDF() 

http://technet.microsoft.com/en-us/library/ms191165(v=sql.105).aspx

0

Se entrambi gli insiemi hanno lo stesso numero di colonne poi

insert into @T1 exec dbo.pVendorBalance 

inserirà l'unione dei due set di dati in @ T1.

Se non

quindi modificare dbo.pVendorBalance e inserire i risultati in tabelle temporanee e in proc esterno memorizzato, scegliere tra quelle tabelle temporanee.

Un altro modo (se ne avete bisogno), si può provare a

SELECT * into #temp 
from OPENROWSET('SQLNCLI', 'Server=(local)\\(instance);Trusted_Connection=yes;', 
'EXEC dbo.pVendorBalance') 

ci vorrà prima dataset.

+2

E se voglio l'ultimo risultato? –

1

ho avuto un requisito analogo, e finito per usare la funzione di un CLR che potete leggere qui (è la risposta con i InsertResultSetsToTables metodo, dall'utente Dan Guzman):

https://social.msdn.microsoft.com/Forums/sqlserver/en-US/da5328a7-5dab-44b3-b2b1-4a8d6d7798b2/insert-into-table-one-or-multiple-result-sets-from-stored-procedure?forum=transactsql

È necessario creare un progetto CLR di SQL Server in Visual Studio per iniziare. Ho avuto un progetto già scritto da un collega di lavoro che ho potuto solo espandersi, ma se si sta iniziando da zero, provare a leggere questa guida:

http://www.emoreau.com/Entries/Articles/2015/04/SQL-CLR-Integration-in-2015-year-not-product-version.aspx

Se sei riuscito a scrivere e pubblicare il progetto CLR per il database, ecco un esempio di usarlo ho scritto:

-- declare a string with the SQL you want to execute (typically an SP call that returns multiple result sets) 
DECLARE @sql NVARCHAR(MAX) 
SET @sql = 'exec usp_SomeProcedure @variable1 = ' + @variable1 + '...' -- piece together a long SQL string from various parameters 

-- create temp tables (one per result set) to hold the output; could also be actual tables (non-temp) if you want 
CREATE TABLE #results_1(
    [CustomerId] INT, [Name] varchar(500), [Address] varchar(500) 
); 

CREATE TABLE #results_2(
    [SomeId] UNIQUEIDENTIFIER, [SomeData] INT, [SomethingElse] DateTime 
); 

-- on the exemplary 'CustomerDatabase' database, there is an SP (created automatically by the SQL CLR project deployment process in Visual Studio) which performs the actual call to the .NET assembly, and executes the .NET code 
-- the CLR stored procedure CLR_InsertResultSetsToTables executes the SQL defined in the parameter @sourceQuery, and outputs multiple result sets into the specified list of tables (@targetTableList) 
EXEC CustomerDatabase.dbo.CLR_InsertResultSetsToTables @sourceQuery = @sql, @targetTableList = N'#results_1,#results_2'; 

-- The output of the SP called in @sql is now dumped in the two temp tables and can be used for whatever in regular SQL 
SELECT * FROM #results_1; 
SELECT * FROM #results_2; 
1

No. Ma v'è di più di un lavoro in giro dal momento che non si può fare un inserto in una procedura che restituisce più risultati con un diverso numero di colonne.

Se è possibile modificare la stored procedure, è possibile dichiarare tabelle temporanee al di fuori della procedura e popolarle all'interno della stored procedure.Quindi puoi fare tutto il necessario con loro al di fuori della stored procedure.

CREATE TABLE # result1 (Ogni colonna è seguita dal tipo di dati del primo risultato.);

---- Esempio: (. Ciascuna colonna seguito dal tipo di dati del secondo risultato) CREATE TABLE # result1 (Colonna1 int, Colonna2 varchar (10))

CREATE TABLE # result2;

EXEC pVendorBalance;

SELECT * FROM # result1;

SELECT * FROM # result2;

+0

Questo è lo schema a cui ho fatto ricorso. Suggerisco caldamente di inserire nella procedura la presenza o meno di tabelle temporanee e di farle rispettare se sono richieste (e di includere la definizione prevista): IF OBJECT_ID ('tempdb .. # name') IS NULL BEGIN RAISERROR ('table #name deve essere dichiarata per acquisire l'output di ProcName', 16, 1) CREATE TABLE #name (colonne ...) END ELEGZA INIZIO ... codice ... END Inoltre elude qualsiasi problema dalla restrizione che il [INSERT EXEC pattern non può essere nidificato] (https://stackoverflow.com/questions/3795263) – Elaskanator

0

Una soluzione a questo problema è l'utilizzo dei parametri OUTPUT (JSON/XML) anziché i gruppi di risultati.

CREATE TABLE tab1(ID INT, Name NVARCHAR(10), Amount MONEY); 
INSERT INTO tab1(ID, Name, Amount) 
VALUES (1, 'Alexander', 10),(2, 'Jimmy', 100), (6, 'Billy', 20); 

CREATE PROCEDURE dbo.pVendorBalance 
AS 
BEGIN 
    -- first resultset 
    SELECT * FROM tab1 WHERE ID <=2; 

    -- second resultset 
    SELECT * FROM tab1 WHERE ID > 5; 
END; 

Versione con params OUT:

CREATE PROCEDURE dbo.pVendorBalance2 
     @resultSet1 NVARCHAR(MAX) OUT, 
     @resultSet2 NVARCHAR(MAX) OUT 
AS 
BEGIN 
    SELECT @resultSet1 = (SELECT * FROM tab1 WHERE ID <=2 FOR JSON AUTO), 
      @resultSet2 = (SELECT * FROM tab1 WHERE ID > 5 FOR JSON AUTO); 
END; 

E ultima chiamata:

DECLARE @r1 NVARCHAR(MAX), @r2 NVARCHAR(MAX); 
EXEC dbo.pVendorBalance2 @r1 OUT, @r2 OUT; 


-- first resultset as table 
SELECT * 
INTO #t1 
FROM OpenJson(@r1) 
WITH (ID int '$.ID', [Name] NVARCHAR(50) '$.Name',Amount money '$.Amount'); 

-- second resultset as table 
SELECT * 
INTO #t2 
FROM OpenJson(@r2) 
WITH (ID int '$.ID', [Name] NVARCHAR(50) '$.Name',Amount money '$.Amount'); 

SELECT * FROM #t1; 
SELECT * FROM #t2; 

DBFiddle Demo

EDIT:

secondo approccio è quello di utilizzare tSQLt.ResultSetFilter funzione CLR (parte del framework di test tSQLt):

La procedura ResultSetFilter offre la possibilità di recuperare un singolo set di risultati da una dichiarazione che produce più set di risultati.

CREATE TABLE #DatabaseSize (
    database_name nvarchar(128), 
    database_size varchar(18), 
    unallocated_space varchar(18) 
); 

CREATE TABLE #ReservedSpaceUsed (
    reserved VARCHAR(18), 
    data VARCHAR(18), 
    index_size VARCHAR(18), 
    unused VARCHAR(18) 
); 

INSERT INTO #DatabaseSize 
EXEC tSQLt.ResultSetFilter 1, 'EXEC sp_spaceused'; 

INSERT INTO #ReservedSpaceUsed 
EXEC tSQLt.ResultSetFilter 2, 'EXEC sp_spaceused'; 

SELECT * FROM #DatabaseSize; 
SELECT * FROM #ReservedSpaceUsed;