有没有办法在SQL Server游标中使用参数?

时间:2011-06-06 18:48:11

标签: sql sql-server tsql cursor

我在数据库中有父子关系。我需要做的是遍历父查询,并使用父的主键,得到它的孩子。我遇到的问题是我需要使用参数化游标(传入密钥)来执行此操作。

在SQL Server中是否有这样的东西或模仿这个?我试过这样做,但它不起作用:

DECLARE @value   VARCHAR(20);
DECLARE @someKey NUMERIC(19,0);

DECLARE main_curs 
CURSOR FOR SELECT value FROM someTable where key = @someKey;

SET @someKey = 12345;

OPEN main_curs
FETCH NEXT FROM main_curs INTO @value;
CLOSE main_curs
DEALLOCATE main_curs

但似乎它没有接我设置@someKey。

对此的任何帮助将不胜感激。谢谢!

更新

我应该包含更多信息,因为我让这个例子看起来太简单了。我有多个需要使用的@someKey值。如前所述,我有亲子关系,最多可以有6个孩子。所以我得到一个父母列表,它是各自的列,并迭代它。在WHILE-LOOP中,我想从父级获取主键并调用另一个游标来获取子信息(返回不同的列)。所以我会对子游标进行多次调用,并设置不同的@someKey值。希望这是有道理的。

7 个答案:

答案 0 :(得分:6)

你需要的是2个游标 - 一个用于父级,一个用于子级。确保子游标在LOOP中是DECLARED而不是在外面。如果你在外面声明它将不起作用。

例如:

DECLARE @value   VARCHAR(20);
DECLARE @someKey NUMERIC(19,0);

DECLARE main_curs 
CURSOR FOR SELECT value FROM someTable where key = @someKey;

SET @someKey = 12345;

OPEN main_curs
FETCH NEXT FROM main_curs INTO @value;
while @@FETCH_STATUS = 0
BEGIN

DECLARE CHILD_CURS CURSOR FOR SELECT VALUE2 FROM CHILDTABLE WHERE value=@value;
open child_curs 
fetch next from child_curs into @x,@y

close child_curs
deallocate child_curs

FETCH NEXT FROM main_curs INTO @value;
END

CLOSE main_curs
DEALLOCATE main_curs

答案 1 :(得分:1)

您可以尝试使用nested cursors。这方面的一个示例位于页面底部,标题为:使用嵌套游标生成报告输出

答案 2 :(得分:1)

以下是如何使用动态SQL声明游标,使用' EXEC()'功能。令人惊讶的是这确实有效。例如:

DECLARE @QuotedDatabase NVARCHAR(128) = QUOTENAME('ReportServer')
DECLARE @ObjectID INT = 389576426
DECLARE @ColumnName NVARCHAR(128)
DECLARE @ColumnType NVARCHAR(128)
DECLARE @DeclareColumnCursor NVARCHAR(4000)
SET @DeclareColumnCursor = '
  DECLARE ColumnCursor CURSOR READ_ONLY FORWARD_ONLY FOR
  SELECT c.Name, t.Name
  FROM ' + @QuotedDatabase + '.sys.columns c
  INNER JOIN ' + @QuotedDatabase + '.sys.types t
  ON c.user_type_id = t.user_type_id
  WHERE c.object_id = ' + CAST(@ObjectID AS NVARCHAR) + '
  ORDER BY column_id'
EXEC(@DeclareColumnCursor)
OPEN ColumnCursor
FETCH NEXT FROM ColumnCursor INTO @ColumnName, @ColumnType
PRINT @ColumnName + ',' + @ColumnType
CLOSE ColumnCursor
DEALLOCATE ColumnCursor

答案 3 :(得分:0)

您需要在光标声明之前设置@someKey = 12345;,例如:

SET @someKey = 12345;
DECLARE main_curs 
CURSOR FOR SELECT value FROM someTable where key = @someKey;

答案 4 :(得分:0)

你似乎有错误的顺序,你实际上没有在光标内做任何事情?

DECLARE @value   VARCHAR(20);
DECLARE @someKey NUMERIC(19,0);

SET @someKey = 12345;   --this has to be set before its used in cursor declaration

DECLARE main_curs 
CURSOR FOR SELECT value FROM someTable where key = @someKey;
OPEN main_curs
FETCH NEXT FROM main_curs INTO @value;     -- first row is fetched

WHILE @@FETCH_STATUS = 0     -- start the loop
BEGIN

-- do something here with @value

FETCH NEXT FROM main_curs INTO @value;   --fetch the next row
END 

CLOSE main_curs
DEALLOCATE main_curs

答案 5 :(得分:0)

如果要迭代递归层次结构,请使用CTE,请参阅Recursive Queries Using Common Table Expressions。您可以将光标声明在递归CTE上,例如:

create table test (
    id int not null identity(1,1) primary key,
    parent_id int null,
    data varchar (max));
go

insert into test (parent_id, data) values 
    (null, 'root'), 
    (1, 'child 1'), 
    (1, 'child 2')  ,
    (2, 'child of child 1'),
    (4, 'child of child of child 1');
go  

declare @root int = 2;

declare crs cursor for 
    with cte as (
        select id, parent_id, data
        from test
        where id = @root
        union all
        select t.id, t.parent_id, t.data
        from test t
            join cte c on t.parent_id = c.id)
    select id, data from cte;       
open crs;

declare @id int, @data varchar(max);
fetch next from crs into @id, @data;
while @@fetch_status = 0
begin
    print @data;
    fetch next from crs into @id, @data;
end

close crs;
deallocate crs;

但是大多数情况下,递归CTE可以完全消除对游标的需求。

答案 6 :(得分:0)

在另一个地方,有人建议使用存储过程(编译SQL而不是ad-hoc脚本),但这也不起作用。这是另一个能够相当清楚地显示问题的MWE:

/* Should print:
dbNamein=master dbNameout=master
dbNamein=model dbNameout=model
dbNamein=msdb dbNameout=msdb
*/
create procedure [TestParamsWithOpenCursorStmt]
as
begin

   declare @dbNameIn [nvarchar](255) = N'tempdb',
      @dbNameOut [nvarchar](255),
      @fs [int];
   declare dbNames cursor for
      select db.[name] from [master].[sys].[databases] db
      where db.[name] = @dbNameIn;
   while (@dbNameIn != N'msdb') begin
      if @dbNameIn = N'tempdb'
         set @dbNameIn = N'master'
      else if @dbNameIn = N'master'
         set @dbNameIn = N'model'
      else if @dbNameIn = N'model'
         set @dbNameIn = N'msdb';
      open dbNames;
      fetch next from dbNames into @dbNameOut;
      set @fs = @@fetch_status;
      if @fs != 0 continue;
      raiserror (N'dbNamein=%s dbNameout=%s', 0, 0, @dbNameIn, @dbNameOut) with nowait;
      close dbNames;
   end;
   deallocate dbNames;

end;
go

execute [TestParamsWithOpenCursorStmt];

似乎变量(及其当时的值)被绑定到"声明...光标"而不是打开光标。