Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/blackberry/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql server 插入到具有多个结果集的with exec中_Sql Server_Tsql_Stored Procedures - Fatal编程技术网

Sql server 插入到具有多个结果集的with exec中

Sql server 插入到具有多个结果集的with exec中,sql-server,tsql,stored-procedures,Sql Server,Tsql,Stored Procedures,SQL Server允许我插入存储过程的返回结果集,如下所示: DECLARE @T TABLE ( ID int, Name varchar(255), Amount money) INSERT INTO @T exec dbo.pVendorBalance 只要存储过程只返回1个结果集,这种方法就有效 如果存储过程返回多个结果集,是否有办法使其正常工作 例如 实际上,存储过程可以返回多个结果集,或者不返回结果集,这是非常任意的。因此,我不知道如何从调用存储过程的其他SQL代

SQL Server允许我插入存储过程的返回结果集,如下所示:

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

INSERT INTO @T
exec dbo.pVendorBalance 
只要存储过程只返回1个结果集,这种方法就有效

如果存储过程返回多个结果集,是否有办法使其正常工作

例如


实际上,存储过程可以返回多个结果集,或者不返回结果集,这是非常任意的。因此,我不知道如何从调用存储过程的其他SQL代码中导航这些结果

CREATE TABLE #result1(Each column followed by data type of first result.);

----Example:  CREATE TABLE #result1(Column1 int, Column2 varchar(10))

CREATE TABLE #result2(Each column followed by data type of second result.);

EXEC pVendorBalance;

SELECT * FROM #result1;

SELECT * FROM #result2;
但是,可以使用表值用户定义函数返回的结果集。它与常规UDF类似,但不是返回标量值,而是返回查询结果。然后您可以像使用任何其他表一样使用该UDF

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

如果两个结果集的列数相同,则

insert into @T1 exec dbo.pVendorBalance
将两个数据集的并集插入@T1

如果不是

然后编辑dbo.pVendorBalance并将结果插入临时表,然后在外部存储过程中,从这些临时表中进行选择

另一种方法如果你需要,你可以试试

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

它将使用第一个数据集。

我有一个类似的要求,并最终使用了一个CLR函数,您可以在这里了解到这是用户Dan Guzman使用InsertResultSetToTables方法的答案:

您需要在VisualStudio中创建一个SQL Server CLR项目才能开始。我的一个同事已经写了一个项目,我可以扩展它,但是如果你是从零开始的,试着阅读以下指南:

如果您已经成功地将CLR项目写入并发布到数据库中,下面是我编写的一个使用该项目的示例:

-- 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;

不可以。但是有更多的解决方法,因为您无法使用返回多个结果且列数不同的过程来执行insert into

如果允许修改存储过程,则可以在过程外部声明临时表,并在存储过程中填充临时表。然后,您可以在存储过程之外对它们执行任何需要的操作

CREATE TABLE #result1(Each column followed by data type of first result.);

----Example:  CREATE TABLE #result1(Column1 int, Column2 varchar(10))

CREATE TABLE #result2(Each column followed by data type of second result.);

EXEC pVendorBalance;

SELECT * FROM #result1;

SELECT * FROM #result2;

解决这个问题的一个方法是使用输出参数JSON/XML而不是结果集

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;
编辑:

第二种方法是使用tSQLt测试框架的CLR功能部分:

ResultSetFilter过程能够从生成多个结果集的语句中检索单个结果集

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;

我们可以用下面的方法来做

考虑输入SP,它返回2个表作为输出作为usp_SourceData

更改usp_SourceData以接受参数1和2

调整SP的方式应确保

usp_SourceData“1”被执行,它将返回第一个表

什么时候


执行usp_SourceData“2”时,它将返回第二个表。

如果我想要最后的结果,这也是我所采用的模式。我强烈建议在过程中检查temp表是否存在,并强制执行它们是否是必需的,并包括预期的定义:if OBJECT_ID'tempdb..name'为NULL BEGIN RAISERROR'table name必须声明才能捕获ProcName的输出,'16,1创建表名列。。。结束,否则开始。。。密码它还避免了“请解释您的答案”限制的任何问题。将存储过程的结果插入临时表,而不定义临时表
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;
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;
DROP TABLE ##Temp

DECLARE @dtmFrom VARCHAR(60) = '2020-12-01 00:00:00', @dtmTo VARCHAR(60) = '2020-12-02 23:59:59.997',@numAdmDscTransID VARCHAR(60) =247054


declare @procname nvarchar(255) = 'spGetCashUnpaidBills', 
        @procWithParam nvarchar(255) = '[dbo].[spGetCashUnpaidBills]  @dtmFromDate= ''' +@dtmFrom+ ''' ,@dtmToDate= ''' +@dtmTo+''',@numCompanyID=1,@numAdmDscTransID='+ @numAdmDscTransID +',@tnyShowIPCashSchemeBills=1',
        @sql nvarchar(max),
        @tableName Varchar(60) = 'Temp'

set @sql = 'create table ##' + @tableName + ' ('
begin
        select      @sql = @sql + '[' + r.name + '] ' +  r.system_type_name + ','
        from        sys.procedures AS p
        cross apply sys.dm_exec_describe_first_result_set_for_object(p.object_id, 0) AS r
        where       p.name = @procname 

        set @sql = substring(@sql,1,len(@sql)-1) + ')'
        execute (@sql)
        execute('insert ##' + @tableName + ' exec ' + @procWithParam)
end

SELECT *FROM ##Temp