如何从内部调用获取记录集到存储过程?

Posted

技术标签:

【中文标题】如何从内部调用获取记录集到存储过程?【英文标题】:How to get recordset from internal call to stored procedure? 【发布时间】:2016-10-04 15:23:10 【问题描述】:

我有一个存储过程,在内部我想调用另一个返回记录集的过程,如何通过'CALL'导航存储过程返回的记录集?

[edit] 我一直在尝试按照建议使用 TEMPORARY TABLE,但遇到了问题:

    DROP TEMPORARY TABLE IF EXISTS tbl_HeadOfDepts;
    CREATE TEMPORARY TABLE tbl_HeadOfDepts (biDept_id tinyint(4))
    INSERT INTO tbl_HeadOfDepts CALL rsHeadOfAnyDepartments(vcCompKey, biWho_id);

我需要使用 CALL,因为 'rsHeadOfAnyDepartments' 不是函数,但这不会被接受。

工作正在进行中,但到目前为止我没有被编辑接受:

    BEGIN
    #--
    # Procedure:
    #   rsWhoCanIaccess
    #
    # Parameters:
    #   vcCompKey, the key corresponding to the company
    #   biWho_id, the id of the person to check access for
    #
    # Returns:
    #   recordset containing all the people this person can access
    #--
        DECLARE tiSuperUser tinyint(4); 
        DECLARE EXIT HANDLER FOR SQLEXCEPTION
            BEGIN
                GET DIAGNOSTICS CONDITION 1 @sqlstate = RETURNED_SQLSTATE, 
                @errno = mysql_ERRNO, @text = MESSAGE_TEXT;
                CALL procLogError(vcCompKey, CONCAT("rsWhoCanIaccess: "
                                        ,@errno, " (", @sqlstate, "): ", @text));
            END;        
    #Is this user a super user?
        SELECT tiIsSuperUser(vcCompKey, biWho_id) INTO tiSuperUser;
        SET tiSuperUser = 0;#Hack for testing
        IF (tiSuperUser = 1) THEN
    #The user is a superuser, return everyone in the company
            SELECT 
                t1.biPerson_id 
            FROM 
                tbl_people t1
            INNER JOIN
                tbl_companies t2
            ON
                t1.biCompany_id=t2.biCompany_id
            AND
                t2.vcKey=vcCompKey;         
        ELSE            
    #User is not a superuser, is the user head of any departments?
            DROP TEMPORARY TABLE IF EXISTS tbl_HeadOfDepts;
            CREATE TEMPORARY TABLE tbl_HeadOfDepts (biDept_id tinyint(4))
            INSERT INTO tbl_HeadOfDepts CALL rsHeadOfAnyDepartments(vcCompKey, biWho_id);

            SELECT * FROM tbl_HeadOfDepts;
        END IF;
    END

【问题讨论】:

【参考方案1】:

不,存储过程可以生成结果集,但不能直接将它们作为内部调用的输出使用到其他存储过程。您可以在性能方面做的最好的事情是填充一个非临时工作表并使用结果。

根据您的软件和多个调用者的实际情况,您可能需要在某些控制表中包含一个带有 auto_increment (AI) 列的会话 ID 概念。这将确保在并发的情况下,多个调用者不会踩到彼此的行,从而使其不可行。

从高层次上讲,该会话的工作方式如下。内部存储过程将从控制表中获得AI 值(theSession),使用它在工作表中填充安全分段的会话,并作为out 参数返回到外部(调用)存储过程。然后,那个外层可以安全地使用这些行,并在最后清理 (delete from workTable where sessionId=theSession)。

为什么我建议使用非临时工作台?需要明确的是,工作台将是非临时的。首先,让if exists drop 工作很麻烦。不过,最重要的是,它与性能有关。用于创建临时表的 DDL 调用并不便宜。只有当您进行性能测试以了解我的意思时,您才会相信这一点。这可能看起来微不足道,但在微不足道的操作中,那些创建 DDL 调用很可能占到完成内部存储过程所需的大部分时间。

【讨论】:

【参考方案2】:

在内部我想调用另一个返回记录集的过程,

在你的内部过程中创建一个TEMPORARY TABLE 并填充那个临时表,上面写着insert into your_temp_table select query。那么你可以在任何地方的外部查询中使用同一个临时表。

它甚至可以是一个普通的表,而不必是临时表。在您的程序计算完成后,请确保DROP 表作为清理。

根据您的评论,这是错误的。你应该像下面那样做(一个示例代码)

create procedure rsHeadOfAnyDepartments(vcCompKey varchar(10), biWho_id int)
as
begin
DROP TEMPORARY TABLE IF EXISTS tbl_HeadOfDepts; 
CREATE TEMPORARY TABLE tbl_HeadOfDepts(col1 int, col2 varchar(10), col3 varchar(30));

INSERT INTO tbl_HeadOfDepts
SELECT col1, col2, col3
FROM tblTest;    
end

【讨论】:

@SPlatten,尝试一下,亲自看看......绝对会奏效。 我不知道该怎么做,我试过这个:DROP TEMPORARY TABLE IF EXISTS tbl_HeadOfDepts;创建临时表 tbl_HeadOfDepts AS INSERT INTO tbl_HeadOfDepts CALL rsHeadOfAnyDepartments(vcCompKey, biWho_id); @SPlatten,这是错误的。如果有帮助,请参阅答案中的编辑。 我不能用'SELECT'调用这个过程,它是一个返回记录集的存储过程,只能用'CALL'调用 recordset 是什么意思?

以上是关于如何从内部调用获取记录集到存储过程?的主要内容,如果未能解决你的问题,请参考以下文章

sqlalchemy 调用 mssql存储过程如何获取返回值?

如何从存储过程调用和获取数据?

如何获取使用 EF Core 从存储过程中插入的记录的 id 值

如何从 Java 调用 MSSQL 加密的存储过程?

如何从 JDBC 中的存储过程中获取输出

如何php调用oracle存储过程返回的是一个结果集,该怎么从php页面中吧数据循环输出呀