1

我有一个运行良好的存储过程,但它里面有三个“选择”。

选择不是来自内部临时表。

这主要是程序的格式:

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

我正在从另一个程序执行该程序,并且需要在那里捕获它。

我创建了一个表并将过程中的“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.

表的列的顺序和名称与过程返回的完全一样。

是否有可能只捕获该过程返回的一个表并避免另一个表?我根本无法改变程序。

我尝试将表声明为与程序的第一个选择相同的字段,但我收到一条错误消息

先感谢您!

4

2 回答 2

0

如果返回的所有结果集都具有相同的结构,那么您可以按照您的尝试将它们转储到临时表中。但是,这只能让您到目前为止,因为如果字段中的数据不能用于确定特定行来自哪个结果集,那么您将拥有所有结果集,而无法过滤掉您没有的结果集想。

单独与多个结果集交互的唯一方法是通过应用程序代码(即客户端连接),无论它们具有相同还是不同的结构。如果您想在另一个查询的上下文中执行此操作,那么您需要使用 SQLCLR。

下面的 C# 代码显示了一个 SQLCLR 存储过程,它将执行一个返回 4 个结果集的 T-SQL 存储过程。它跳过前 2 个结果集,只返回第 3 个结果集。这允许根据需要在 INSERT...EXEC 中使用 SQLCLR 存储过程。

以下代码调用的 T-SQL 存储过程的代码显示在 C# 代码块下方。T-SQL 测试过程执行sp_who2并仅返回该过程返回的字段的子集,表明您不需要返回与正在读取的完全相同的结果集;它可以在运输过程中被操纵。

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。如果您只想要第一个结果集,只需删除两者_ResultSetsToSkipfor循环。

  • _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 proc,以便它们可以用于设置某些SqlParameters的值

然后使用如下:

INSERT INTO #stalledp 
         (RowNumber,fldid,fldLastUpdated,fldCreationDate,fldName,fldPending)
EXEC Get3rdResultSetFromGetStuckWorkflowInstances;
于 2015-02-16T17:10:12.723 回答
-1

有办法获得第一个记录集,但其他的,恐怕,你不走运。

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

如果存储过程中的查询返回空值,则会在过程中的该点引发异常。不过,这仅适用于 sql server 2012 及更高版本。

于 2015-02-15T12:16:53.980 回答