在存储过程中接收少数结果集中的一个
Receiving one out of few Result Sets in stored procedure
我有一个工作正常的存储过程,但它里面有三个 "select"s。
select 不是来自内部临时 table。
这个主要是程序的格式:
ALTER PROCEDURE [dbo].[STProce]
@param1 int,
@param2 int,
@param3 int,
@param4 int,
@param5 int
AS
select @param1 as p1, @param2 as p2, @param3 as p3
.
.
.
select @param4 as p4
.
.
.
select @param5 as p5
我正在执行另一个过程中的过程,需要在那里捕获它。
我创建了一个 table 并从程序中插入了 "exec",就像这样:
CREATE TABLE #stalledp
(
RowNumber INT,
fldid INT,
fldLastUpdated datetime,
fldCreationDate datetime,
fldName nvarchar(255),
fldPending nvarchar(255)
)
INSERT INTO #stalledp (RowNumber,fldid,fldLastUpdated,fldCreationDate,fldName,fldPending)
EXEC spDebuggerViews_GetStuckWorkflowInstances @workflowSpaceId='00000000-0000-0000-0000-000000000000',@pageNum=1,@pageSize=100000,@orderByColumn=N'fldid',@sortOrder=1,@workflowInstanceId=0,@stuckInstanceType=1,@createdDateFrom='1900-01-01 00:00:00',@createdDateTo='9999-01-01 23:59:59',@updatedDateFrom='1900-01-01 00:00:00',@updatedDateTo='9999-01-01 23:59:59'
之后我收到这个错误:
Column name or number of supplied values does not match table definition.
table 的列的顺序和名称与过程 returns 完全相同。
是否有可能只捕获过程 returns 中的一个 table 而避免另一个?我根本无法更改程序。
我尝试声明一个 table 与过程的第一个 select 相同的字段,但我收到一条错误消息说
提前致谢!
有一种方法可以获得第一个记录集,但恐怕你运气不好。
EXEC sp_addlinkedserver @server = 'LOCALSERVER', @srvproduct = '',
@provider = 'SQLOLEDB', @datasrc = @@servername
SELECT * FROM OPENQUERY(LOCALSERVER, 'EXEC testproc2')
编辑: 如果您只需要检查其他结果集的列不为空,您可以像这样预定义预期的结果集:
EXEC testproc2 WITH RESULT SETS (
(a VARCHAR(MAX) NOT NULL, b VARCHAR(MAX) NOT NULL),
(a VARCHAR(MAX) NOT NULL)
);
如果存储过程中的查询 returns 为空值,则会在过程中的那个点引发异常。这仅适用于 sql 服务器 2012 及更高版本。
如果所有 returned 的结果集都具有相同的结构,那么您可以将它们转储到临时 table,就像您尝试做的那样。但是,这只能让你走到这一步,因为如果字段中的数据不能用于确定特定行来自哪个结果集,那么你只有所有的结果集,无法过滤掉你不想要的结果集想要。
与多个结果集单独交互的唯一方法是通过应用程序代码(即客户端连接),而不管它们具有相同或不同的结构。如果您想在另一个查询的上下文中执行此操作,则需要使用 SQLCLR.
下面的 C# 代码显示了一个 SQLCLR 存储过程,它将执行一个 T-SQL 存储过程,returns 4 个结果集。它跳过前 2 个结果集,仅 returns 第三个结果集。这允许 SQLCLR 存储过程根据需要在 INSERT...EXEC 中使用。
以下代码调用的T-SQL存储过程的代码显示在C#代码块下方。 T-SQL 测试过程执行 sp_who2
并且只有 return 字段的子集被该过程 return 编辑,表明您不需要 return 与您正在阅读的结果集完全相同;它可以在运输过程中被操纵。
C# SQLCLR 过程:
using System;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;
public class TheProc
{
[Microsoft.SqlServer.Server.SqlProcedure]
public static void Get3rdResultSetFromGetStuckWorkflowInstances()
{
int _ResultSetsToSkip = 2; // we want the 3rd result set
SqlConnection _Connection = null;
SqlCommand _Command = null;
SqlDataReader _Reader = null;
try
{
_Connection = new SqlConnection("Context Connection = true;");
_Command = _Connection.CreateCommand();
_Command.CommandType = CommandType.StoredProcedure;
_Command.CommandText = "tempdb.dbo.MultiResultSetTest";
// (optional) add parameters (but don't use AddWithValue!)
// The SqlDataRecord will be used to define the result set structure
// and act as a container for each row to be returned
SqlDataRecord _ResultSet = new SqlDataRecord(
new SqlMetaData[]
{
new SqlMetaData("SPID", SqlDbType.Char, 5),
new SqlMetaData("Status", SqlDbType.NVarChar, 30),
new SqlMetaData("Login", SqlDbType.NVarChar, 128),
new SqlMetaData("HostName", SqlDbType.NVarChar, 128),
new SqlMetaData("BlkBy", SqlDbType.VarChar, 5),
new SqlMetaData("DBName", SqlDbType.NVarChar, 128)
});
SqlContext.Pipe.SendResultsStart(_ResultSet); // initialize result set
_Connection.Open();
_Reader = _Command.ExecuteReader();
// Skip a predefined number of result sets
for (int _Index = 0;
_Index < _ResultSetsToSkip && _Reader.NextResult();
_Index++) ;
// Container used to move 1 full row from the result set being read
// to the one being sent, sized to the number of fields being read
Object[] _TempRow = new Object[_Reader.FieldCount];
while (_Reader.Read())
{
_Reader.GetValues(_TempRow); // read all columns
_ResultSet.SetValues(_TempRow); // set all columns
SqlContext.Pipe.SendResultsRow(_ResultSet); // send row
}
}
catch
{
throw;
}
finally
{
if(SqlContext.Pipe.IsSendingResults)
{
SqlContext.Pipe.SendResultsEnd(); // close out result set being sent
}
if(_Reader != null && !_Reader.IsClosed)
{
_Reader.Dispose();
}
_Command.Dispose();
if (_Connection != null && _Connection.State != ConnectionState.Closed)
{
_Connection.Dispose();
}
}
return;
}
}
T-SQL 测试过程:
USE [tempdb]
SET ANSI_NULLS ON;
IF (OBJECT_ID('dbo.MultiResultSetTest') IS NOT NULL)
BEGIN
DROP PROCEDURE dbo.MultiResultSetTest;
END;
GO
CREATE PROCEDURE dbo.MultiResultSetTest
AS
SET NOCOUNT ON;
SELECT 1 AS [ResultSet], 'asa' AS [test];
SELECT 2 AS [ResultSet], NEWID() AS [SomeGUID], GETDATE() AS [RightNow];
EXEC sp_who2;
SELECT 4 AS [ResultSet], CONVERT(MONEY, 131.12) AS [CashYo];
GO
EXEC tempdb.dbo.MultiResultSetTest;
待办事项:
适当调整_ResultSetsToSkip
。如果您只想要第一个结果集,只需删除 _ResultSetsToSkip
和 for
循环。
适当定义_ResultSet
设置_Command.CommandText
为"spDebuggerViews_GetStuckWorkflowInstances"
通过SqlParameter
(即@workflowSpaceId='00000000-0000-0000-0000-000000000000',@pageNum=1,@pageSize=100000,@orderByColumn=N'fldid',@sortOrder=1,@workflowInstanceId=0,@stuckInstanceType=1,@createdDateFrom='1900-01-01 00:00:00',@createdDateTo='9999-01-01 23:59:59',@updatedDateFrom='1900-01-01 00:00:00',@updatedDateTo='9999-01-01 23:59:59'
)创建必要的参数
如果需要,将输入参数添加到 SQLCLR 过程,以便它们可用于设置某些 SqlParameter
s
[= 的值60=]
然后使用如下:
INSERT INTO #stalledp
(RowNumber,fldid,fldLastUpdated,fldCreationDate,fldName,fldPending)
EXEC Get3rdResultSetFromGetStuckWorkflowInstances;
我有一个工作正常的存储过程,但它里面有三个 "select"s。
select 不是来自内部临时 table。
这个主要是程序的格式:
ALTER PROCEDURE [dbo].[STProce]
@param1 int,
@param2 int,
@param3 int,
@param4 int,
@param5 int
AS
select @param1 as p1, @param2 as p2, @param3 as p3
.
.
.
select @param4 as p4
.
.
.
select @param5 as p5
我正在执行另一个过程中的过程,需要在那里捕获它。
我创建了一个 table 并从程序中插入了 "exec",就像这样:
CREATE TABLE #stalledp
(
RowNumber INT,
fldid INT,
fldLastUpdated datetime,
fldCreationDate datetime,
fldName nvarchar(255),
fldPending nvarchar(255)
)
INSERT INTO #stalledp (RowNumber,fldid,fldLastUpdated,fldCreationDate,fldName,fldPending)
EXEC spDebuggerViews_GetStuckWorkflowInstances @workflowSpaceId='00000000-0000-0000-0000-000000000000',@pageNum=1,@pageSize=100000,@orderByColumn=N'fldid',@sortOrder=1,@workflowInstanceId=0,@stuckInstanceType=1,@createdDateFrom='1900-01-01 00:00:00',@createdDateTo='9999-01-01 23:59:59',@updatedDateFrom='1900-01-01 00:00:00',@updatedDateTo='9999-01-01 23:59:59'
之后我收到这个错误:
Column name or number of supplied values does not match table definition.
table 的列的顺序和名称与过程 returns 完全相同。
是否有可能只捕获过程 returns 中的一个 table 而避免另一个?我根本无法更改程序。
我尝试声明一个 table 与过程的第一个 select 相同的字段,但我收到一条错误消息说
提前致谢!
有一种方法可以获得第一个记录集,但恐怕你运气不好。
EXEC sp_addlinkedserver @server = 'LOCALSERVER', @srvproduct = '',
@provider = 'SQLOLEDB', @datasrc = @@servername
SELECT * FROM OPENQUERY(LOCALSERVER, 'EXEC testproc2')
编辑: 如果您只需要检查其他结果集的列不为空,您可以像这样预定义预期的结果集:
EXEC testproc2 WITH RESULT SETS (
(a VARCHAR(MAX) NOT NULL, b VARCHAR(MAX) NOT NULL),
(a VARCHAR(MAX) NOT NULL)
);
如果存储过程中的查询 returns 为空值,则会在过程中的那个点引发异常。这仅适用于 sql 服务器 2012 及更高版本。
如果所有 returned 的结果集都具有相同的结构,那么您可以将它们转储到临时 table,就像您尝试做的那样。但是,这只能让你走到这一步,因为如果字段中的数据不能用于确定特定行来自哪个结果集,那么你只有所有的结果集,无法过滤掉你不想要的结果集想要。
与多个结果集单独交互的唯一方法是通过应用程序代码(即客户端连接),而不管它们具有相同或不同的结构。如果您想在另一个查询的上下文中执行此操作,则需要使用 SQLCLR.
下面的 C# 代码显示了一个 SQLCLR 存储过程,它将执行一个 T-SQL 存储过程,returns 4 个结果集。它跳过前 2 个结果集,仅 returns 第三个结果集。这允许 SQLCLR 存储过程根据需要在 INSERT...EXEC 中使用。
以下代码调用的T-SQL存储过程的代码显示在C#代码块下方。 T-SQL 测试过程执行 sp_who2
并且只有 return 字段的子集被该过程 return 编辑,表明您不需要 return 与您正在阅读的结果集完全相同;它可以在运输过程中被操纵。
C# SQLCLR 过程:
using System;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;
public class TheProc
{
[Microsoft.SqlServer.Server.SqlProcedure]
public static void Get3rdResultSetFromGetStuckWorkflowInstances()
{
int _ResultSetsToSkip = 2; // we want the 3rd result set
SqlConnection _Connection = null;
SqlCommand _Command = null;
SqlDataReader _Reader = null;
try
{
_Connection = new SqlConnection("Context Connection = true;");
_Command = _Connection.CreateCommand();
_Command.CommandType = CommandType.StoredProcedure;
_Command.CommandText = "tempdb.dbo.MultiResultSetTest";
// (optional) add parameters (but don't use AddWithValue!)
// The SqlDataRecord will be used to define the result set structure
// and act as a container for each row to be returned
SqlDataRecord _ResultSet = new SqlDataRecord(
new SqlMetaData[]
{
new SqlMetaData("SPID", SqlDbType.Char, 5),
new SqlMetaData("Status", SqlDbType.NVarChar, 30),
new SqlMetaData("Login", SqlDbType.NVarChar, 128),
new SqlMetaData("HostName", SqlDbType.NVarChar, 128),
new SqlMetaData("BlkBy", SqlDbType.VarChar, 5),
new SqlMetaData("DBName", SqlDbType.NVarChar, 128)
});
SqlContext.Pipe.SendResultsStart(_ResultSet); // initialize result set
_Connection.Open();
_Reader = _Command.ExecuteReader();
// Skip a predefined number of result sets
for (int _Index = 0;
_Index < _ResultSetsToSkip && _Reader.NextResult();
_Index++) ;
// Container used to move 1 full row from the result set being read
// to the one being sent, sized to the number of fields being read
Object[] _TempRow = new Object[_Reader.FieldCount];
while (_Reader.Read())
{
_Reader.GetValues(_TempRow); // read all columns
_ResultSet.SetValues(_TempRow); // set all columns
SqlContext.Pipe.SendResultsRow(_ResultSet); // send row
}
}
catch
{
throw;
}
finally
{
if(SqlContext.Pipe.IsSendingResults)
{
SqlContext.Pipe.SendResultsEnd(); // close out result set being sent
}
if(_Reader != null && !_Reader.IsClosed)
{
_Reader.Dispose();
}
_Command.Dispose();
if (_Connection != null && _Connection.State != ConnectionState.Closed)
{
_Connection.Dispose();
}
}
return;
}
}
T-SQL 测试过程:
USE [tempdb]
SET ANSI_NULLS ON;
IF (OBJECT_ID('dbo.MultiResultSetTest') IS NOT NULL)
BEGIN
DROP PROCEDURE dbo.MultiResultSetTest;
END;
GO
CREATE PROCEDURE dbo.MultiResultSetTest
AS
SET NOCOUNT ON;
SELECT 1 AS [ResultSet], 'asa' AS [test];
SELECT 2 AS [ResultSet], NEWID() AS [SomeGUID], GETDATE() AS [RightNow];
EXEC sp_who2;
SELECT 4 AS [ResultSet], CONVERT(MONEY, 131.12) AS [CashYo];
GO
EXEC tempdb.dbo.MultiResultSetTest;
待办事项:
适当调整
_ResultSetsToSkip
。如果您只想要第一个结果集,只需删除_ResultSetsToSkip
和for
循环。适当定义
_ResultSet
设置
_Command.CommandText
为"spDebuggerViews_GetStuckWorkflowInstances"通过
SqlParameter
(即@workflowSpaceId='00000000-0000-0000-0000-000000000000',@pageNum=1,@pageSize=100000,@orderByColumn=N'fldid',@sortOrder=1,@workflowInstanceId=0,@stuckInstanceType=1,@createdDateFrom='1900-01-01 00:00:00',@createdDateTo='9999-01-01 23:59:59',@updatedDateFrom='1900-01-01 00:00:00',@updatedDateTo='9999-01-01 23:59:59'
)创建必要的参数如果需要,将输入参数添加到 SQLCLR 过程,以便它们可用于设置某些
[= 的值60=]SqlParameter
s
然后使用如下:
INSERT INTO #stalledp
(RowNumber,fldid,fldLastUpdated,fldCreationDate,fldName,fldPending)
EXEC Get3rdResultSetFromGetStuckWorkflowInstances;