0

簡単に言うと、私の質問は、カーソル(擬似コード)を使用せずに、t-sql2012で次のことを行う方法です。

for each r in input_list:

    insert into t1(...) ...

    if (r.field1 is not null)
        insert into tA(...) (...@@identity ...   r.field1) ... 

    else if (r.field2 is not null)
        insert into tB(...) (...@@identity...    r.field2)  ...

長い質問:

次の3つのテーブルがあり、オブジェクトがファイルまたはディレクトリのいずれかであるという事実をモデル化するとします。

obj(id int, creation_date datetime)  -- all objects have a creation date.
file(id int, id_obj int, path nvarchar(max))  -- id_obj is a foreign key to obj
dir(id int, id_obj int, path nvarchar(max), shared bit) -- id_obj is a foreign key to obj

「論理オブジェクト」(ファイルまたはdirのいずれかを表すことができます)のリストを取得してDBに追加するストアドプロシージャを作成する必要があります。つまり、論理オブジェクトごとに1)objに行を作成する必要があります。 2)ファイルまたはディレクトリのいずれかの行(論理オブジェクトがファイルを表すかディレクトリを表すかによって異なります)。

このストアドプロシージャを作成するために、論理オブジェクトを表すテーブルパラメータを作成しました。これは、ファイルとdirの両方を表すことができる必要があるため、次のように、fileとdirの(論理)フィールドのマージが含まれている必要があります。

create type logicalObj as table(
                                dirPath nvarchar(max) null, 
                                dirShared bit null,  
                                filePath nvarchar(max) null
                               )

私のストアドプロシージャは、次のようにテーブル値パラメーターで定義されています。

create procedure foo 
       -- this way the user can pass a list of logical objects to the stored proc
   @lo logicalObj readonly  .

as
begin
...
end

プロシージャ本体で、(擬似コード)のようなことをする必要があると思います。

for each lo in @lo:

    insert into obj(creation_date)
        values (curdate())

    if lo.dirPath is not null
        insert into dir(id_obj, path, shared)
        values (@@identity, lo.dirPath, 1 )
    else if lo.filePath is not null
        insert into file(id_obj, path)
        values (@@identity, lo.dirPath )

私の質問:カーソルなしでこれを行う方法は?必要に応じて、t-sql 2012に固有の機能(シーケンスなど)を使用してもかまいません。

4

2 に答える 2

1

outputを使用して、最初のセットベースの挿入からの ID 値を持つ複数の行をキャプチャできます。その後、句を使用ROW_NUMBER()して、これらのキャプチャされた出力値を元の@lo変数の行と関連付けることができます。

次のようになります。

declare @IDs table (ID int not null)
insert into obj(creation_date)
output inserted.id into @IDs
select curdate() from @lo --Just makes sure there's one row per row in @lo

;with NumberedIDs as (
     select ID,ROW_NUMBER() OVER (ORDER BY ID) as rn from @IDs
), NumberedObjects as (
     select *,ROW_NUMBER() OVER (ORDER BY dirPath,filePath) as rn from @lo
)
insert into dir (id_obj, path, shared)
select nid.ID,no.dirPath,no.dirShared
from NumberedObjects no
       inner join
     NumberedIDs nid
       on
         no.rn = nid.rn
where
   no.dirPath is not null

;with NumberedIDs as (
     select ID,ROW_NUMBER() OVER (ORDER BY ID) as rn from @IDs
), NumberedObjects as (
     select *,ROW_NUMBER() OVER (ORDER BY dirPath,filePath) as rn from @lo
)
insert into file (id_obj, path)
select nid.ID,no.filePath
from NumberedObjects no
       inner join
     NumberedIDs nid
       on
         no.rn = nid.rn
where
   no.filePath is not null

行番号が一致し続けるように、下の 2 つの挿入で完全にクエリ@loを実行しNumberedObjects、フィルター処理が早すぎないようにすることが重要です。

于 2013-02-13T11:12:27.327 に答える
0

なぜそれを3つのインサートとしてやらないのですか?

このようなもの:

INSERT into obj(creation_date)
SELECT curdate() FROM @lo WHERE (lo.dirPath is not null) OR (lo.dirPath is null AND lo.filePath is not null)

insert into dir(id_obj, path, shared)
SELECT @@identity, lo.dirPath, 1 FROM @lo WHERE lo.dirPath is not null

insert into file(id_obj, path)
SELECT @@identity, lo.dirPath, 1 FROM @lo lo WHERE lo.dirPath is null AND lo.filePath is not null
于 2013-02-13T11:12:06.950 に答える