【发布时间】: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
我可以在过程中传递游标吗?
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
我假设您使用的是 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 包(这不是微不足道的!)
【讨论】:
来自MSDN (SQL Server 2008):游标数据类型只能用于 OUTPUT 参数。指定游标数据类型时,还必须指定 VARYING 和 OUTPUT 关键字。您可以使用游标数据类型指定多个输出参数。
【讨论】:
关于 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
【讨论】:
这在 MSSQL2005 中是不可能的。我不知道 2008 或其他平台。
有好几次我想这样做。它将支持更加模块化的架构。我可以有一个 proc 对数据集执行一个常见的过程,但能够将光标从各种其他过程传递到该数据集。
【讨论】:
建议可能使用视图的答案假设其意图是能够使用相同查询的结果执行两种不同的算法。当然,这是传递游标的一种用途,但对我来说,我想用两个不同查询的结果执行相同的算法。我有两个程序,每个程序都有自己的目的和一个有意义的名称,它们碰巧基于不同的查询共享相同的算法,因此每个程序都会使用适当的查询打开游标,然后调用一个通用程序来执行算法。
那么,为什么不将查询的 SQL 传递给文本,让内部过程在那里打开游标呢?因为如果你这样做并且 SQL 有任何绑定变量,你需要将它们与文本一起传递,这意味着两个(或更多)查询不仅需要返回相同的列集,它们还必须采用相同的数字和绑定变量的类型。如果您传递游标,则打开游标并且变量绑定在声明 SQL 的过程的上下文中,但在游标传递到的过程的上下文中处理的行。
【讨论】: