sql >> データベース >  >> RDS >> Sqlserver

階層データをコピーするときに親子関係を保持する

    CTEはMERGEとうまく連携します 、ただしSQLServer2005では問題があります。以前の誤解を招くコメントについては申し訳ありません。

    以下は、プロジェクト(複数のツリーを含む)のクローンを作成し、親子関係を修正して新しいフォレストを古いフォレストから分離する方法を示しています。 Idの特定の配置に依存しないことに注意してください。密度が高く、単調に増加する必要はありません...。

    -- Sample data.
    declare @Projects as Table
      ( Id Int Identity, ProjectId Int, Value VarChar(16), ParentId Int Null );
    insert into @Projects ( ProjectId, Value, ParentId ) values
      ( 611, 'Animal', 0 ),
      ( 611, 'Frog', 1 ),
      ( 611, 'Cow', 1 ),
      ( 611, 'Jersey Cow', 3 ),
      ( 611, 'Plant', 0 ),
      ( 611, 'Tree', 5 ),
      ( 611, 'Oak', 6 );
    -- Display the raw data.
    select * from @Projects;
    
    -- Display the forest.
    with IndentedProjects ( Id, ProjectId, Value, ParentId, Level, Path ) as
      ( -- Start with the top level rows.
      select Id, ProjectId, Value, ParentId, 0, Convert( VarChar(1024), Right( '000' + Convert( VarChar(4), Id ), 4 ) )
        from @Projects
        where ParentId = 0
      union all
      -- Add the children one level at a time.
      select P.Id, P.ProjectId, P.Value, P.ParentId, IP.Level + 1, Convert( VarChar(1024), IP.Path + '<' + Right( '000' + Convert( VarChar(4), P.Id ), 4 ) )
        from IndentedProjects as IP inner join
          @Projects as P on P.ParentId = IP.Id
      )
      select Space( Level * 2 ) + Value as [IndentedValue], Id, ProjectId, Value, ParentId, Level, Path
        from IndentedProjects
        order by Path;
    
    -- Clone the project.
    declare @OldProjectId as Int = 611;
    declare @NewProjectId as Int = 42;
    declare @Fixups as Table ( OldId Int, [NewId] Int );
    begin transaction -- With suitable isolation since the hierarchy will be invalid until we apply the fixups!
    insert into @Projects
      output Inserted.ParentId, Inserted.Id
        into @Fixups
      select @NewProjectId, Value, Id -- Note that we save the old Id in the new ParentId.
        from @Projects as P
        where ProjectId = @OldProjectId;
    -- Apply the fixups.
    update PNew
      set ParentId = IsNull( FNew.[NewId], 0 )
      -- Output the fixups just to show what is going on.
      output Deleted.Id, Deleted.ParentId as [ParentIdBeforeFixup], Inserted.ParentId as [ParentIdAfterFixup]
      from @Fixups as F inner join
        @Projects as PNew on PNew.Id = F.[NewId] inner join -- Rows we need to fix.
        @Fixups as FOld on FOld.OldId = PNew.ParentId inner join
        @Projects as POld on POld.Id = FOld.OldId left outer join
        @Fixups as FNew on FNew.OldId = POld.ParentId;
    commit transaction;
    
    -- Display the forest.
    with IndentedProjects ( Id, ProjectId, Value, ParentId, Level, Path ) as
      ( -- Start with the top level rows.
      select Id, ProjectId, Value, ParentId, 0, Convert( VarChar(1024), Right( '000' + Convert( VarChar(4), Id ), 4 ) )
        from @Projects
        where ParentId =0
      union all
      -- Add the children one level at a time.
      select P.Id, P.ProjectId, P.Value, P.ParentId, IP.Level + 1, Convert( VarChar(1024), IP.Path + '<' + Right( '000' + Convert( VarChar(4), P.Id ), 4 ) )
        from IndentedProjects as IP inner join
          @Projects as P on P.ParentId = IP.Id
      )
      select Space( Level * 2 ) + Value as [IndentedValue], Id, ProjectId, Value, ParentId, Level, Path
        from IndentedProjects
        order by Path;
    


    1. MySQLで主キーを削除する

    2. OrderBy句を使用したMySQLのランク関数

    3. 警告:mysql_result()は、パラメーター1がリソースであり、ブール値が指定されていることを想定しています。

    4. リレーショナルモデル