6

次のテーブルで構成されるスキーマを想定します。

バズ

BazID (PK, Identity)
Description

FooTemplate(Bazには0から多数のFooTemplateが含まれる場合があります)

FooTemplateID (PK, Identity)
BazID (FK)
Description
NextGenerationDate

BarTemplate(FooTemplateには0から多数のBarTemplateが含まれる場合があります)

BarTemplateID (PK, Identity)
FooTemplateID (FK)
Description

Foo(A Bazには0から多数のFooが含まれる場合があります)

FooID (PK, Identity) 
BazID (FK)
Description

バー(A Fooには0から多数のバーがある場合があります)

BarID (PK, Identity)
FooID (FK)
Description

ストアドプロシージャが毎日実行され、次の生成日を過ぎた関連エンティティのエンティティが生成Fooされます。BarBaz

この手順の最初の部分は、次のようになります。

DECLARE @GeneratedFooIDList TABLE (INT FooID);
INSERT Foo (BazID, Description)
OUTPUT inserted.FooID INTO @GeneratedFooIDList
SELECT
  BazID
  Description
FROM
  FooTemplate
WHERE
  NextGenerationDate < GETDATE()

私の質問は、適切なエンティティを生成し、それらを新しく作成されたエンティティBarに適切に関連付けるために、どのステートメントを実行できるかということです。Foo

編集:プロシージャは、SQLServer2005を実行しているサーバーで実行されます。

EDIT2:助けてくれたみんなに感謝します。情報を注意深く検討した後、私は別の解決策を選びました。Fooテーブルの主キーを自動生成されたID列ではないように変更しました。これにより、一時テーブルへの中間挿入を実行して、FooIDとともに関連するFooTemplateIDをキャプチャできます。

4

2 に答える 2

2

私があなたのスキーマを正しく理解していれば

declare @GeneratedFooIDList table (FooID int, FooTemplateID int)
declare @Date datetime = getdate()

/*
insert Foo (BazID, Description)
    output inserted.FooID, FT.FooTemplateID into @GeneratedFooIDList
select
    FT.BazID,
    FT.Description
from FooTemplate as FT
where
    FT.NextGenerationDate < @Date
*/

merge into Foo using
(
    select *
    from FooTemplate as FT
    where
        NextGenerationDate < @Date
) as FT on 1 = 0
when not matched then
insert (BazID, Description)
values (BazID, Description)
output inserted.FooID, FT.FooTemplateID into @GeneratedFooIDList;

insert Bar (FooID, Description)
select
    G.FooID
    BT.Description
from BarTemplate as BT
    inner join @GeneratedFooIDList as G on G.FooTemplateID = BT.FooTemplateID

SQL Server 2005を使用している場合、これは機能しません。(BazID, Description)テーブル内の組み合わせの一意性に依存するため、別の解決策を提案できFooTemplateます。また、役立つ場合は、日付<@DateのfooTemplateの変数テーブルで書き直すこともできます。

http://sqlfiddle.com/#!3/ee576/29

declare @GeneratedFooIDList table (FooID int)
declare @Date datetime = getdate()

insert Foo (BazID, Description)
    output inserted.FooID into @GeneratedFooIDList
select
    FT.BazID,
    FT.Description
from FooTemplate as FT
where
    FT.NextGenerationDate < @Date

insert Bar (FooID, Description)
select
    G.FooID,
    BT.Description
from @GeneratedFooIDList as G
    inner join Foo as F on F.FooID = G.FooID
    inner join FooTemplate as FT on FT.BazID = F.BazID and FT.Description = F.Description
    inner join BarTemplate as BT on BT.FooTemplateID = FT.FooTemplateID
于 2012-10-23T13:01:07.423 に答える
1

これは、BazIDごとにFooTemplateが1つだけであり、FooTemplateごとにBarTemplateが1つしかないという大きな仮定になります。そうでない場合、構造により、どのbazがどのfooテンプレートに対応し、どのbartemplateがどのfootemplateに対応するかを特定することが困難になります。一意性を確保するために、PKまたはUQを使用せずに、[説明]列に入力する必要があります。独自性を確信することはできません。

INSERT Bar (FooID, Description)
 select new.FooId, bt.Description
  from @GeneratedFooIDList new
   inner join Foo f
    on f.FooId = new.FooId
   inner join FooTemplate  ft  --  one to one assumption here
    on ft.BazID = f.BazID
   inner join BarTemplate bt  --  another one to one assumption here
    on bt.FooTemplateId = ft.FooTemplateId

@RomanPekarによると、一時テーブルにFooTemplateIdを追加できれば、この後の更新は簡単になりますが、正しいのは、output句が機能するだけです(新しいID列の処理を開始すると非常に煩雑になりますinserteddeleted


[追加した]

コアの問題を要約する方法は次のとおりです。

  • Fooテーブルに多くの行を追加します
  • 各行には、新しく生成された代理キー(FooId)があります
  • これらの新しいFooエンティティごとに、 0個以上のバー行を生成する必要があります。
  • したがって、「ソース」FooTemplateの必要なBarTemplate行を取得するには、新しい各行を元のFooTemplate行にマップして戻す必要があります。
  • ただし、Fooテーブルには、このマッピングを有効にするものはありません(たとえば、FooをそのソースFooTemplateにリンクします。複数のテンプレートが存在する可能性があるため、BazIdを使用できません。説明を使用することはできません。一意性を保証するものではありません
  • また、このリンクはINSERT…OUTPUT…コンストラクトによって提供することもできません。これは、Fooテーブルに挿入された列のみを抽出できるためです。

この種の問題に対して過去に使用した解決策の1つは、新しいテーブル(Foo)の列にリンクデータを一時的に入力することです。ここでは、FooTemplateIdをFoo.Descriptionに格納し、それに基づいて必要なINSERT…SELECTを作成し、そのIDでFooTemplateにリンクされているFooを更新して、descriptionを適切な値に置き換えます。それは動作しますが、厄介です。

@MikaelErikssonの不幸にも削除された投稿と参照リンク(特に心配をやめてMERGEを愛する方法)に基づく別の解決策は mergeコマンド を使用することです。その出力句。これを使用して、一時テーブルに新しいFooIDとソースFooTemplateIdを入力し、そこから作業します。(テストおよびデバッグするためのサンプルデータがないため、このプロセスを作成するためのMERGEスキルに十分な自信がありませんが、実行できると確信しています。)

于 2012-10-23T13:52:38.870 に答える