7

データベースに親子関係があります。私がする必要があるのは、親のクエリをループし、親の主キーを使用してその子を取得することです。私が抱えている問題は、これを行うにはパラメーター化されたカーソル (キーを渡す) を使用する必要があることです。

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 値を設定して、子カーソルを複数回呼び出します。それが理にかなっていることを願っています。

4

7 に答える 7

6

必要なものは 2 つのカーソルです。1 つは親用で、もう 1 つは子用です。子カーソルが LOOP の外側ではなく内側で宣言されていることを確認してください。外側で宣言すると機能しません。

例:

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
于 2012-10-12T19:30:45.930 に答える
1

別の場所では、誰かがストアド プロシージャ (アドホック スクリプトではなくコンパイル済み SQL) を使用することを提案しましたが、それも機能しません。これは、問題をかなり明確に示す別の 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];

変数 (およびその時点での値) は、開いているカーソルではなく「declare ... カーソル」にバインドされているようです。

于 2016-12-12T18:11:02.023 に答える
1

試してみることのできることの 1 つは、ネストされたカーソルを使用することです。この例は、「ネストされたカーソルを使用してレポート出力を生成する」というタイトルのページの下部にあります。

于 2011-06-06T19:11:17.227 に答える
0

@someKey = 12345;次のようなカーソル宣言の前に設定する必要があります。

SET @someKey = 12345;
DECLARE main_curs 
CURSOR FOR SELECT value FROM someTable where key = @someKey;
于 2011-06-06T18:50:51.823 に答える
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
于 2011-06-06T18:51:03.573 に答える
0

CTE を使用して再帰的な階層を反復処理する場合は、共通テーブル式を使用した再帰クエリを参照してください。再帰 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 はカーソルの必要性を完全になくすことができます。

于 2011-06-06T19:33:52.327 に答える