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

Откуда:
Сообщений: 662
Добрый день.

SELECT @@version
---
Microsoft SQL Server 2005 - 9.00.4035.00 (X64) 
	Nov 24 2008 16:17:31 
	Copyright (c) 1988-2005 Microsoft Corporation
	Enterprise Edition (64-bit) on Windows NT 5.2 (Build 3790: Service Pack 2)

Есть необходимость формировать новый XML из "корневого" и XML_ей полученных из "корневого" после некой обработки по следующим правилам (для узлов):
1) Если узел есть в "корневом" XML_е и во всех остальных XML_ях, то его нужно оставить. При этом позиция узлов важна !!!
2) Если узел отсутствует в "корневом" XML_е и присутствует только в одном экземпляре, то его нужно добавить в конец нового XML_я. При этом порядок добавления в конец НЕ важен.
3) Все остальные узлы не попавшие в пп.1 и пп.2 не должны попасть в новый XML

Т.е. нужно сначала добавить все узлы из п.п. 1 с сохранением позиции и в произвольном порядке дописать в конец узлы из п.п. 2

Анализируются узлы только второго уровня по уникальному атрибуту "ID". В процессе работы новые узлы всегда добавляются в конец XML_я.

Тестовые данные:
declare @NodeName sysname, @SubCnt int
set @NodeName = 'Node'

declare @t table( ident int identity(1,1), Val xml )

-- Корневой XML
insert into @t
select '<Root><Node ID="5"/><Node ID="3"/></Root>'

-- Набор XML_ей полученых из корневого
insert into @t
--select '<Root><Node ID="5"/><Node ID="3"/><Node ID="8"/></Root>' union ALL
select '<Root><Node ID="5"/><Node ID="8"/></Root>' union ALL
select '<Root><Node ID="5"/><Node ID="3"/><Node ID="4"/></Root>' union ALL
select '<Root><Node ID="5"/><Node ID="3"/><Node ID="9"/></Root>' union ALL
select '<Root><Node ID="5"/><Node ID="3"/></Root>' 

SELECT @SubCnt = Count(*)-1
FROM @t

SELECT *
FROM(
  select i.id, 0 as [isNew]
  from @t as t
  cross apply(
    select n.c.value('@ID', 'sysname') as [ID]
    from t.Val.nodes('/*/*[local-name()=sql:variable("@NodeName")]') as n(c)
  ) as i
  where t.ident = 1

  UNION ALL

  SELECT t.id, 1 as [isNew]
  FROM (
    select i.id
    from @t as t
    cross apply(
      select n.c.value('@ID', 'sysname') as [ID]
      from t.Val.nodes('/*/*[local-name()=sql:variable("@NodeName")]') as n(c)
    ) as i
    where t.ident != 1

    EXCEPT
    
    select i.id
    from @t as t
    cross apply(
      select n.c.value('@ID', 'sysname') as [ID]
      from t.Val.nodes('/*/*[local-name()=sql:variable("@NodeName")]') as n(c)
    ) as i
    WHERE t.ident = 1
  ) as T
) A

--CROSS APPLY(
--  SELECT Count(*) as [cnt]
--  FROM @t as t
--  CROSS APPLY(
--    SELECT n.c.value('@NODE_NAME', 'sysname') as [name]
--    FROM t.Val.nodes('/*/*[local-name()=sql:variable("@NodeName") and @ID=sql:column("A.ID")]') as n(c)
--  ) as c
--  WHERE t.ident != 1
--) as c
--
--CROSS APPLY(
--  SELECT 1 as [OK]
--  WHERE (A.[isNew] = 0) and (c.[cnt] = @SubCnt)
--
--  UNION ALL
--
--  SELECT 1 as [OK]
--  WHERE (A.[isNew] = 1) and (c.[cnt] = 1)
--) as OK
--

Закоментарены корректные условия для получения нужного результата, НО если их раскоментарить, то позиция узлов тут-же теряется (что понятно).

Вопрос - как не потерять позицию узлов из п.п. 1 ?
2 июн 09, 14:35    [7256125]     Ответить | Цитировать Сообщить модератору
 Re: Формирование узлов XML_я  [new]
daw
Member

Откуда: Муром -> Москва
Сообщений: 7381

если я правильно понял, суть вопроса - пронумеровать
ноды в исходном xml в порядке их следования?

Posted via ActualForum NNTP Server 1.4

2 июн 09, 14:59    [7256298]     Ответить | Цитировать Сообщить модератору
 Re: Формирование узлов XML_я  [new]
mike909
Member

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

Во, стоило только написать вопрос, как ответ нарисовался сам собой ....
SELECT TOP 1 WITH TIES *
FROM(
  select i.id, 0 as [isNew], i.Pos
  from @t as t
  cross apply(
    select n.c.value('@ID', 'sysname') as [ID],
           n.c.value('count(for $s in(../*[local-name()=sql:variable("@NodeName")]) where $s << . return(.))', 'int') + 1 as [Pos]
    from t.Val.nodes('/*/*[local-name()=sql:variable("@NodeName")]') as n(c)
  ) as i
  where t.ident = 1

  UNION ALL

  SELECT t.id, 1 as [isNew], 0x7FFFFFFF as [Pos]
  FROM (
    select i.id
    from @t as t
    cross apply(
      select n.c.value('@ID', 'sysname') as [ID]
      from t.Val.nodes('/*/*[local-name()=sql:variable("@NodeName")]') as n(c)
    ) as i
    where t.ident != 1

    EXCEPT
    
    select i.id
    from @t as t
    cross apply(
      select n.c.value('@ID', 'sysname') as [ID]
      from t.Val.nodes('/*/*[local-name()=sql:variable("@NodeName")]') as n(c)
    ) as i
    WHERE t.ident = 1
  ) as T
) A

CROSS APPLY(
  SELECT Count(*) as [cnt]
  FROM @t as t
  CROSS APPLY(
    SELECT n.c.value('@NODE_NAME', 'sysname') as [name]
    FROM t.Val.nodes('/*/*[local-name()=sql:variable("@NodeName") and @ID=sql:column("A.ID")]') as n(c)
  ) as c
  WHERE t.ident != 1
) as c

CROSS APPLY(
  SELECT 1 as [OK]
  WHERE (A.[isNew] = 1) and (c.[cnt] = 1)

  UNION ALL

  SELECT 1 as [OK]
  WHERE (A.[isNew] = 0) and (c.[cnt] = @SubCnt)

) as OK

CROSS APPLY(
  SELECT top 1 t.Val.query('/*/*[local-name()=sql:variable("@NodeName") and @ID=sql:column("A.ID")]') as [node]
  FROM @t as t
  WHERE t.Val.exist('/*/*[local-name()=sql:variable("@NodeName") and @ID=sql:column("A.ID")]') = 1
    --and t.ident != 1 
) as NL
ORDER BY row_number() over(partition by Pos, A.ID order by Pos)  

P.S. Если есть идеи получше, то поделитесь плз....
2 июн 09, 15:02    [7256308]     Ответить | Цитировать Сообщить модератору
 Re: Формирование узлов XML_я  [new]
mike909
Member

Откуда:
Сообщений: 662
daw

если я правильно понял, суть вопроса - пронумеровать
ноды в исходном xml в порядке их следования?



Вот именно, как только до меня это дошло ....
2 июн 09, 15:05    [7256326]     Ответить | Цитировать Сообщить модератору
Все форумы / Microsoft SQL Server Ответить