2016-04-26 6 views
0

私は[#relationtree]と呼ばれる一時テーブルにその言うことができます、次のように私の親、子キーのセットのリストを与える再帰CTEを持っている:親/子キーテーブルが与えられた場合、構造のコピーを再帰的に別のテーブルに挿入するにはどうすればよいですか?

Parent | Child 
-------------- 
1  | 3 
3  | 5 
5  | 6 
5  | 9 

私はこれらのコピーを作成したいですどのように私は上記のレコードを挿入するが、再帰の各コピーのParentIdは列としてその値を挿入できるようにするには、以前に挿入されたID値を取得することができ

CREATE TABLE [dbo].[Relations] 
(
    [Id] int identity(1,1) 
    [ParentId] int 
) 

:とテーブルへの関係は、以下のstuctureを言うことができます私は挿入する子供ですか?

私は[DBO]このの終わりに持つことが期待される。[関係](我々の現在のシード値をされて与えられ、50を言う)

Id | ParentId 
------------- 
... other rows present before this query ... 
50 | NULL 
51 | 50 
52 | 51 
53 | 51 

私はSCOPE_IDENTITYがで働くことができることをわかりません新しいIDのリストを含む新しい一時表を作成し、ID列を手動で挿入するのが正しい方法ですか?

私はこれを行うためにカーソル/ループを書くことができましたが、いくつかの再帰的な選択魔法を実行するいい方法が必要です!

+0

申し訳ありませんが、私は二回あなたの質問を経て、しかしmuch..particularlyこれを理解することはできません:出力

DECLARE @offset INT = IDENT_CURRENT('#relations') ;WITH relationtreeids AS ( SELECT *, ROW_NUMBER() OVER(ORDER BY Parent, Child) - 2 AS UnmodifiedParentId -- Simulate an identity field FROM #relationtree ) INSERT INTO #relations -- The LAG window function allows you to inspect the previous row SELECT CASE WHEN LAG(Parent) OVER(ORDER BY Parent) IS NULL THEN NULL WHEN LAG(Parent) OVER(ORDER BY Parent) = Parent THEN UnmodifiedParentId + @offset ELSE UnmodifiedParentId + @offset + 1 END AS ParentId FROM relationtreeids 

部。 "私は上記のレコードを挿入することができますが再帰的に挿入された子の各コピーのParentId列としてその値を挿入できるように以前に挿入されたID値を取得する? 。いくつかのサンプル入力と期待出力のいくつかのサンプルデータを提供することができます – TheGameiswar

答えて

1

テーブルのセグメントにツリーを配置しようとしているので、テーブルにはSET IDENTITY_INSERT ONを使用する必要があるようです。あなたは、新しいツリーのための余地があることを確認する必要があります。この場合、テーブル内の現在の最大値はidであると仮定します。これにより、テーブルの後にあるツリーがオーバーランすることに気を付ける必要がなくなります。

古いツリーのIDを新しいツリーにマップする必要があります。

SET IDENTITY_INSERT dbo.Relations ON 

;WITH CTE_MappedIDs AS 
(
    SELECT 
     old_id, 
     ROW_NUMBER() OVER(ORDER BY old_id) + 49 AS new_id 
    FROM 
    (
     SELECT DISTINCT parent AS old_id FROM #relationtree 
     UNION 
     SELECT DISTINCT child AS old_id FROM #relationtree 
    ) SQ 
) 
INSERT INTO dbo.Relations (Id, ParentId) 
SELECT 
    CID.new_id, 
    PID.new_id 
FROM 
    #relationtree RT 
INNER JOIN CTE_MappedIDs PID ON PID.old_id = RT.parent 
INNER JOIN CTE_MappedIDs CID ON CID.old_id = RT.parent 
-- We need to also add the root node 
UNION ALL 
SELECT 
    NID.new_id, 
    NULL 
FROM 
    #relationtree RT2 
INNER JOIN CTE_MappedIDs NID ON NID.old_id = RT2.parent 
WHERE 
    RT2.parent NOT IN (SELECT DISTINCT child FROM #relationtree) 

SET IDENTITY_INSERT dbo.Relations OFF 

私がいることが、場合をテストしていません:IDSの周りにいくつかのルールがありますしない限り、このような何かを行うような場合には、私は思いますので、正確なマッピングは、それが正確だ限り無関係でなければなりませんそれは期待どおりに動作しませんし、うまくいけば正しい方向にあなたを指します。

+0

乾杯、見てみましょう。既存のレコードの間にツリーを挿入したいのではなく、テーブルの末尾に追加するだけで(IDENTITY INSERTは必要ありません) –

+0

このメソッドは、マッピングのためにテーブルの最後にあっても 'IDENTITY_INSERT'を必要とします。あなたは、同じトランザクション内のテーブルで 'SELECT MAX(id)...'を実行して得た値でコード内の "49"を置き換えることができます。 –

+1

ポインタありがとう!いくつかの調整を行い、私のシナリオに合ったものにしました。マッピングロジックは必要なステップでした! –

0

私はあなたが既に実用的な答えを持っていることを知っていますが、前の行を検査するためにLAG関数を使用して同じことをもう少し簡単に行うことができます(Tom Hの答えで何かが間違っているとは限りません) SQL Server 2012以降を使用していることを前提としています。

セットアップ:

CREATE TABLE #relationtree (
    Parent INT, 
    Child INT 
) 

CREATE TABLE #relations (
    Id INT IDENTITY(1,1), 
    ParentId INT 
) 

INSERT INTO #relationtree (Parent, Child) VALUES(1,3), (3,5), (5,6), (5,9) 

INSERT INTO #relations (ParentId) values(1), (3), (5) 

ソリューション:

Id ParentId 
1 1 
2 3 
3 5 
4 NULL 
5 4 
6 5 
7 5 
関連する問題