【问题标题】:Can I pass a cursor in a procedure?我可以在过程中传递游标吗?
【发布时间】:2008-12-15 13:20:25
【问题描述】:

我可以在过程中传递游标吗?

CURSOR  BLT_CURSOR IS
SELECT  BLT.sol_id,
        BLT.bill_id,
        BLT.bank_id
FROM BLT;

是我的光标。

Procedure abc(i want to pass the cursor here)

我该怎么做。

【问题讨论】:

    标签: sql


    【解决方案1】:

    我假设您使用的是 Oracle(看起来是这样)。

    你可以这样做:

    PROCEDURE abc( p_cursor IN SYS_REFCURSOR) IS
       v_sol_id blt.sol_id%TYPE;
       v_bill_id blt.bill_id%TYPE;
       v_bank_id blt.bank_id%TYPE;
    BEGIN
       LOOP
          FETCH p_cursor INTO v_sol_id, v_bill_id, v_bank_id;
          EXIT WHEN p_cursor%NOTFOUND;
          ...
       END LOOP;
    END;
    

    然后使用它:

    DECLARE
       v_cursor SYS_REFCURSOR;
    BEGIN
       OPEN v_cursor FOR
          SELECT  BLT.sol_id,
                  BLT.bill_id,
                  BLT.bank_id
          FROM BLT;
       abc (v_cursor);
       CLOSE v_cursor;
    END;
    

    但是,请注意过程 abc 需要知道游标的结构,即它返回 3 列特定类型。如果您希望能够将 any 游标传递给该过程,那么您需要考虑使用 DBMS_SQL 包(这不是微不足道的!)

    【讨论】:

      【解决方案2】:

      来自MSDN (SQL Server 2008):游标数据类型只能用于 OUTPUT 参数。指定游标数据类型时,还必须指定 VARYING 和 OUTPUT 关键字。您可以使用游标数据类型指定多个输出参数。

      【讨论】:

      • 所以在 T-SQL 上下文中原始问题的答案是“不,你不能”?
      【解决方案3】:

      关于 MS-SQL,您不能将光标作为输入参数传递。您只能将光标作为输出参数传递。
      您可以做的是将光标选择子句文本作为输入参数传递。您可能会发现下面的工作代码很有用。

      --Create the table and fill it with data
      DROP   TABLE    dbo.StackOverflow_MyTable
      GO
      CREATE TABLE    dbo.StackOverflow_MyTable (
                      MyChar      varchar(10),
                      MyDate      datetime,
                      MyNum       numeric(10,2)
                      PRIMARY KEY (MyChar))
      GO
      INSERT INTO dbo.StackOverflow_MyTable SELECT 'A1', '2018-01-13', 123.45
      INSERT INTO dbo.StackOverflow_MyTable SELECT 'B2', '2018-01-14', 123.46
      INSERT INTO dbo.StackOverflow_MyTable SELECT 'C3', '2018-01-15', 123.47
      GO
      /* Create the procedure which returns the cursor variable based on select statement
         The cursor must be opened here. Otherwise it throws an Error:
         The variable '@MyCursorVar' does not currently have a cursor allocated to it
      */
      DROP   PROCEDURE dbo.StackOverflow_OpenCursor
      GO
      CREATE PROCEDURE dbo.StackOverflow_OpenCursor @SelectSQL nvarchar(128), @MyCursorVar CURSOR VARYING OUTPUT
          AS
          DECLARE @SQL nvarchar(256)
          SET @SQL='  SET     @MyCursorVar = CURSOR FOR '+@SelectSQL+'
                      OPEN    @MyCursorVar'
      
          EXEC sp_executesql @SQL, N'@MyCursorVar CURSOR OUTPUT', @MyCursorVar OUTPUT
      GO
      
      --Create the procedure which browses the table using the cursor variable
      DROP   PROCEDURE dbo.StackOverflow_BrowseCursor
      GO
      CREATE PROCEDURE dbo.StackOverflow_BrowseCursor @SelectSQL nvarchar(128)
          AS
          --Create the cursor variable based on select statement and OPEN the cursor
          DECLARE @MyCursorVar CURSOR
          EXEC dbo.StackOverflow_OpenCursor @SelectSQL, @MyCursorVar OUTPUT
      
          --Declare the variables corresponding to table column
          DECLARE @MyChar varchar(10), @MyDate datetime, @MyNum numeric(10,2)
          --Browse record by record
          WHILE 1=1
          BEGIN
              FETCH NEXT FROM @MyCursorVar INTO @MyChar, @MyDate, @MyNum
              IF @@FETCH_STATUS <> 0 BREAK
              PRINT @MyChar   --Here you might call any other procedure or dataset update
              PRINT @MyDate
              PRINT @MyNum
          END
          --release the cursor resources
          CLOSE       @MyCursorVar
          DEALLOCATE  @MyCursorVar
      GO
      
      --How to call the cursor browsing 
      DECLARE @SelectSQL nvarchar(128)
      SET     @SelectSQL = 'SELECT MyChar, MyDate, MyNum FROM dbo.StackOverflow_MyTable ORDER BY MyChar'
      EXEC dbo.StackOverflow_BrowseCursor @SelectSQL
      

      【讨论】:

        【解决方案4】:

        这在 MSSQL2005 中是不可能的。我不知道 2008 或其他平台。

        有好几次我想这样做。它将支持更加模块化的架构。我可以有一个 proc 对数据集执行一个常见的过程,但能够将光标从各种其他过程传递到该数据集。

        【讨论】:

        • 为什么投反对票?这回答了问题(“否”),并添加了有关问题为何重要的信息。
        【解决方案5】:

        建议可能使用视图的答案假设其意图是能够使用相同查询的结果执行两种不同的算法。当然,这是传递游标的一种用途,但对我来说,我想用两个不同查询的结果执行相同的算法。我有两个程序,每个程序都有自己的目的和一个有意义的名称,它们碰巧基于不同的查询共享相同的算法,因此每个程序都会使用适当的查询打开游标,然后调用一个通用程序来执行算法。

        那么,为什么不将查询的 SQL 传递给文本,让内部过程在那里打开游标呢?因为如果你这样做并且 SQL 有任何绑定变量,你需要将它们与文本一起传递,这意味着两个(或更多)查询不仅需要返回相同的列集,它们还必须采用相同的数字和绑定变量的类型。如果您传递游标,则打开游标并且变量绑定在声明 SQL 的过程的上下文中,但在游标传递到的过程的上下文中处理的行。

        【讨论】:

        • 人们可能会寻找一种方法来避免动态 SQL 以从更好的计划缓存中受益......这就是我遇到这个问题的方式。
        猜你喜欢
        • 2023-01-10
        • 2010-09-21
        • 1970-01-01
        • 2018-11-03
        • 1970-01-01
        • 2015-10-13
        • 2015-09-15
        • 2014-08-22
        • 2021-11-26
        相关资源
        最近更新 更多