Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Microsoft SQL Server Новый топик    Ответить
 создать копию узла дерева иерархии  [new]
waszkiewicz
Member

Откуда:
Сообщений: 1086
Таблица, представляющая иерархию
{id;parentid;val}
id - identity

как в общем случае клонировать ветку? Выбрать элементы, подлежащие копированию, вставить, получить новые id - не проблема,как потом переподчинить это дело?
Только одна бредовая идея крутится - добавить еще и temp_id и туда складывать "старые" id. Но как-то ....
27 мар 17, 12:04    [20336355]     Ответить | Цитировать Сообщить модератору
 Re: создать копию узла дерева иерархии  [new]
лолл
Member

Откуда:
Сообщений: 450
waszkiewicz,

логично, что сначала нужно получить идентификатор новой ветви, поэтому необходимо произвести вставку. затем в этой же транзакции добавить (или переместить имеющиеся) на созданную ветвь нужные поддеревья. для деревьев вместо identity-полей удобнее использовать последовательности. в таком случае можно подготавливать некоторую часть дерева отдельно, сгенерировав для нее нужные идентификаторы (например, в табличную переменную), а потом одним оператором произвести вставку в физическую таблицу.
27 мар 17, 13:21    [20336788]     Ответить | Цитировать Сообщить модератору
 Re: создать копию узла дерева иерархии  [new]
aleksrov
Member

Откуда:
Сообщений: 948
Думаю можно быстрее
if OBJECT_ID('tempdb..#t') is not null 
drop table #t; 

with cte as  
( 
SELECT d.Id,d.Name,d.Parent_Id 
  FROM [TSQL2012].[dbo].[Departs] as d 
  where  d.Parent_Id is null and id=9 -- 9 т.к. для надо было выбрать конкретную ветвь
  union all  
  select d.Id,d.Name,d.Parent_Id 
  FROM [TSQL2012].[dbo].[Departs] as d  
  join cte as c  
  on d.Parent_Id = c.Id 
 ) 
  
SELECT *, ROW_NUMBER() over(order by (select null))  as NId 
 into #t 
  FROM CTE 

select t2.NId, t2.Name, t1.NId from #t as t1 right join #t as t2 on t1.id=t2.Parent_id 
drop table #t
27 мар 17, 13:44    [20336883]     Ответить | Цитировать Сообщить модератору
 Re: создать копию узла дерева иерархии  [new]
waszkiewicz
Member

Откуда:
Сообщений: 1086
aleksrov,
быстрее это хорошо, однако неверно ибо identity.
27 мар 17, 14:50    [20337215]     Ответить | Цитировать Сообщить модератору
 Re: создать копию узла дерева иерархии  [new]
waszkiewicz
Member

Откуда:
Сообщений: 1086
waszkiewicz,
только это смог осилить. (добавил новое поле в таблицу)
большой вопрос в многопользовательской среде - взлетит ли?
declare @temp table(id int)
begin tran
 ;with cte as
(
	select id
			,ref
			,isparent
			,parentid 
	from objects where id=@id
	union all
	select o.id
			,o.ref
			,o.isparent
			,o.parentid 
from objects o join cte c on o.parentid=c.id
)
insert objects (parentid,ref,isparent,sequence) output inserted.id into @temp
select parentid,ref,isparent,id from cte

update o set o.parentid=o1.id
from objects o join objects o1
on o.parentid=o1.sequence
where o.id>(select top 1 id from @temp order by id)

update  o set parentid=o1.id
from objects o join objects o1 on o.parentid=o1.id 
where o.id=(select top 1 id from @temp order by id)

insert ObjectsModels (o_id,pl_type)
	select id ,@template from @temp

commit tran
27 мар 17, 15:21    [20337392]     Ответить | Цитировать Сообщить модератору
 Re: создать копию узла дерева иерархии  [new]
лолл
Member

Откуда:
Сообщений: 450
waszkiewicz,

да, именно поэтому я и рекомендовал снять identity и поставить default constraint на последовательность.

ну а если не хотите снимать, то ловите вставки через SCOPE_IDENTITY() в случае единичной вставки и через
INSERT
OUTPUT
INTO

в случае вставки нескольких ветвей одновременно.
27 мар 17, 15:23    [20337404]     Ответить | Цитировать Сообщить модератору
 Re: создать копию узла дерева иерархии  [new]
лолл
Member

Откуда:
Сообщений: 450
waszkiewicz,

ужас, а не решение. для клонирования поддерева с элемента @Id вам нужно вставить новую ветвь @NewId, затем прочитать рекурсией всех детей ветви @id и скопировать их, изменив у верхних ветвей Parent_Id на @NewId
27 мар 17, 15:29    [20337430]     Ответить | Цитировать Сообщить модератору
 Re: создать копию узла дерева иерархии  [new]
waszkiewicz
Member

Откуда:
Сообщений: 1086
да вопрос вот в чем
where o.id>(select top 1 id from @temp order by id)


если одновременно кто-то вставит ветки то первый
1 увидит все вставленные
2 только свои
3 иное

нужно ли в случаи 1 ограничивать еще и сверху?
Ну и главный вопрос пока открыт - без доп.поля в objects возможно как-то это реализовать?
27 мар 17, 15:32    [20337455]     Ответить | Цитировать Сообщить модератору
 Re: создать копию узла дерева иерархии  [new]
лолл
Member

Откуда:
Сообщений: 450
waszkiewicz,

а нет, я поторопился, вы же не переносите ветви, а клонируете... тем более тогда лучше снять identity, либо придется заполнять в цикле по одному уровню, т.к. для добавления каждого чилда вам нужно сначала сгенерировать id родителя...
27 мар 17, 15:37    [20337485]     Ответить | Цитировать Сообщить модератору
 Re: создать копию узла дерева иерархии  [new]
waszkiewicz
Member

Откуда:
Сообщений: 1086
лолл
waszkiewicz,

ужас, а не решение. для клонирования поддерева с элемента @Id вам нужно вставить новую ветвь @NewId, затем прочитать рекурсией всех детей ветви @id и скопировать их, изменив у верхних ветвей Parent_Id на @NewId


на ужас больше ответ похож. особенно про
лолл
изменив у верхних ветвей Parent_Id на @NewId

была бы это просто ветка - и вопрос не возник бы. А так-то ветка и сама вполне себе родитель
27 мар 17, 15:43    [20337513]     Ответить | Цитировать Сообщить модератору
 Re: создать копию узла дерева иерархии  [new]
invm
Member

Откуда: Москва
Сообщений: 9400
+
use tempdb;
go

create table dbo.t (id int identity primary key, parent_id int, data varchar(10));

set identity_insert dbo.t on;
insert into dbo.t
 (id, parent_id, data)
values
 (1, null, 'a'), (2, 1, 'b'), (3, 1, 'c'), (4, 3, 'd'), (5, 4, 'e'), (6, 3, 'f');
set identity_insert dbo.t off;
go

select * from dbo.t;
go

declare @source_branch_id int = 3, @target_branch_id int = null;
declare @a table (id int, id_old int, parent_id_old int);

with s as
(
 select
  id, parent_id, data
 from
  dbo.t
 where
  id = @source_branch_id

 union all

 select
  t.id, t.parent_id, t.data
 from
  s join
  dbo.t on t.parent_id = s.id
)
merge into dbo.t
using s on 1 = 0
when not matched then
 insert (parent_id, data) values (case when s.id = @source_branch_id then @target_branch_id else s.parent_id end, s.data)
output
 inserted.id, s.id, inserted.parent_id into @a;

update t
 set
  parent_id = a2.id
from
 @a a1 join
 dbo.t on t.id = a1.id join
 @a a2 on a2.id_old = a1.parent_id_old;

select * from dbo.t;
go

drop table dbo.t;
go
27 мар 17, 15:59    [20337579]     Ответить | Цитировать Сообщить модератору
 Re: создать копию узла дерева иерархии  [new]
TaPaK
Member

Откуда: Kiev
Сообщений: 6801
invm,

а для понимания: зачем мерж?
27 мар 17, 16:03    [20337602]     Ответить | Цитировать Сообщить модератору
 Re: создать копию узла дерева иерархии  [new]
waszkiewicz
Member

Откуда:
Сообщений: 1086
а, так вот в чем дело

from_table_name
Префикс столбца, который обозначает таблицу, содержащуюся в предложении FROM инструкции DELETE, UPDATE или MERGE; эти инструкции указывают обновляемые или удаляемые строки.

каюсь, MERGE никогда не пользовал
27 мар 17, 16:04    [20337605]     Ответить | Цитировать Сообщить модератору
 Re: создать копию узла дерева иерархии  [new]
лолл
Member

Откуда:
Сообщений: 450
waszkiewicz
каюсь, MERGE никогда не пользовал


в данном варианте MERGE можно заменить и на
INSERT
OUTPUT
INTO
27 мар 17, 16:10    [20337639]     Ответить | Цитировать Сообщить модератору
 Re: создать копию узла дерева иерархии  [new]
waszkiewicz
Member

Откуда:
Сообщений: 1086
лолл,

особенно
27 мар 17, 16:13    [20337650]     Ответить | Цитировать Сообщить модератору
 Re: создать копию узла дерева иерархии  [new]
invm
Member

Откуда: Москва
Сообщений: 9400
TaPaK
а для понимания: зачем мерж?
Чтобы иметь возможность сложить в output столбец из таблицы-источника.
лолл
в данном варианте MERGE можно заменить
Нельзя.
27 мар 17, 16:13    [20337655]     Ответить | Цитировать Сообщить модератору
 Re: создать копию узла дерева иерархии  [new]
waszkiewicz
Member

Откуда:
Сообщений: 1086
waszkiewicz
Только одна бредовая идея крутится - добавить еще и temp_id и туда складывать "старые" id. Но как-то ....
27 мар 17, 16:14    [20337658]     Ответить | Цитировать Сообщить модератору
 Re: создать копию узла дерева иерархии  [new]
TaPaK
Member

Откуда: Kiev
Сообщений: 6801
invm
TaPaK
а для понимания: зачем мерж?
Чтобы иметь возможность сложить в output столбец из таблицы-источника.
лолл
в данном варианте MERGE можно заменить
Нельзя.

о как, буду знать, хоть не пользуюсь, мне OUTPUT не доступен, по архитектуре :(
27 мар 17, 16:26    [20337755]     Ответить | Цитировать Сообщить модератору
 Re: создать копию узла дерева иерархии  [new]
лолл
Member

Откуда:
Сообщений: 450
invm
TaPaK
а для понимания: зачем мерж?
Чтобы иметь возможность сложить в output столбец из таблицы-источника.
лолл
в данном варианте MERGE можно заменить
Нельзя.


а-а, действительно, просмотрел, что идет вставка значения из секции using, которая не пошла в dbo.t.. да есть такой момент для MERGE... жаль, что в INSERT OUTPUT нельзя использовать поля секции FROM.. кстати, не в курсе, почему так?
27 мар 17, 16:34    [20337803]     Ответить | Цитировать Сообщить модератору
 Re: создать копию узла дерева иерархии  [new]
invm
Member

Откуда: Москва
Сообщений: 9400
лолл
жаль, что в INSERT OUTPUT нельзя использовать поля секции FROM.. кстати, не в курсе, почему так?
Потому что в insert, в отличие от update, delete и merge, нет секции from или using.
27 мар 17, 16:43    [20337833]     Ответить | Цитировать Сообщить модератору
 Re: создать копию узла дерева иерархии  [new]
лолл
Member

Откуда:
Сообщений: 450
invm,

спасибо)
27 мар 17, 17:17    [20337949]     Ответить | Цитировать Сообщить модератору
 Re: создать копию узла дерева иерархии  [new]
iljy
Member

Откуда:
Сообщений: 8711
invm
лолл
жаль, что в INSERT OUTPUT нельзя использовать поля секции FROM.. кстати, не в курсе, почему так?
Потому что в insert, в отличие от update, delete и merge, нет секции from или using.


Ну в принципе в конструкции INSERT .. SELECT .. FROM секция FROM таки есть, но почему-то тут решили не заморачиваться и из секции OUTPUT доступа к ней не давать. MERGE проблему решает, но выглядит диковато и не слишком наглядно.
27 мар 17, 17:26    [20337989]     Ответить | Цитировать Сообщить модератору
 Re: создать копию узла дерева иерархии  [new]
invm
Member

Откуда: Москва
Сообщений: 9400
iljy
Ну в принципе в конструкции INSERT .. SELECT .. FROM секция FROM таки есть
Формально, согласно синтаксиса, все-таки нет. Потому что from относится не к insert, а к derived_table или dml_table_source.
Так что все логично, ведь в select и т.п. невозможно обратиться к таблицам из derived_table.
27 мар 17, 18:27    [20338179]     Ответить | Цитировать Сообщить модератору
Все форумы / Microsoft SQL Server Ответить