SQL Server 2008 XML заменяет значения элементов текстом из других значений элементов - PullRequest
1 голос
/ 16 января 2012

Со следующей таблицей:

CREATE TABLE [dbo].[GDB_ITEMS](
    [ObjectID] [int] NOT NULL,
    [UUID] [uniqueidentifier] NOT NULL,
    [Type] [uniqueidentifier] NOT NULL,
    [Name] [nvarchar](226) NULL,
    [PhysicalName] [nvarchar](226) NULL,
    [Path] [nvarchar](512) NULL,
    [Url] [nvarchar](255) NULL,
    [Properties] [int] NULL,
    [Defaults] [varbinary](max) NULL,
    [DatasetSubtype1] [int] NULL,
    [DatasetSubtype2] [int] NULL,
    [DatasetInfo1] [nvarchar](255) NULL,
    [DatasetInfo2] [nvarchar](255) NULL,
    [Definition] [xml] NULL,
    [Documentation] [xml] NULL,
    [ItemInfo] [xml] NULL,
    [Shape] [geometry] NULL,
 CONSTRAINT [R2_pk] PRIMARY KEY CLUSTERED 
(
    [ObjectID] ASC
)

Столбец xml documentation содержит эту группу элементов 1:

<spdom>
  <bounding>
    <westbc>-84.007769</westbc>
    <eastbc>-83.037582</eastbc>
    <northbc>35.790660</northbc>
    <southbc>35.418718</southbc>
  </bounding>
</spdom>

и эта группа элементов 2:

<GeoBndBox esriExtentType="search">
  <westBL Sync="TRUE">-84.024010</westBL>
  <eastBL Sync="TRUE">-82.992641</eastBL>
  <northBL Sync="TRUE">35.845552</northBL>
  <southBL Sync="TRUE">35.417139</southBL>
  <exTypeCode Sync="TRUE">1</exTypeCode>
</GeoBndBox>

То, что я хотел бы сделать программно, это заменить значения в группе 1 значениями в группе 2. Например, westbc и westBL - это одно и то же определение, поэтому я бы хотел заменить -84.007769 на -84,024010. Попытка сделать это для нескольких тысяч записей в gdb_items, каждая с различными текстовыми значениями в этой группе элементов. Спасибо!

1 Ответ

1 голос
/ 16 января 2012

Вы должны использовать заменить значение (XML DML) .

Синтаксис, используемый для замены значения westbc на 10, выглядит следующим образом.

update GDB_ITEMS
set Documentation.modify(
  'replace value of (//spdom/bounding/westbc/text())[1] with "10"')

И чтобы получить необходимое вам значение, вы должны использовать что-то вроде этого:

select Documentation.value('(//GeoBndBox/westBL)[1]', 'varchar(20)')
from GDB_ITEMS

Соединение этих двух в одном операторе обновления.

update T
set Documentation.modify(
  'replace value of (//spdom/bounding/westbc/text())[1] 
   with sql:column("S.Value")')
from GDB_ITEMS as T
  cross apply (select T.Documentation.value('(//GeoBndBox/westBL)[1]', 
                                            'varchar(20)')) as S(Value) 

Невозможно заменить значение более чем в одном узле за раз, поэтому вы должны повторить это для каждого узла. Вы можете сделать это довольно хорошо в цикле, используя таблицу карт, которая имеет имя исходного узла и имя целевого узла.

declare @Map table
(
  ID int identity primary key,
  TargetNode varchar(7),  
  SourceNode varchar(7)
)

insert into @Map values
('westbc',  'westBL'),
('eastbc',  'eastBL'),
('northbc', 'northBL'),
('southbc', 'southBL')

declare @ID int = 1

while @ID <= 4
begin
  update T 
  set Documentation.modify('replace value of 
                              (//spdom/bounding/*[local-name(.)=sql:column("M.TargetNode")]/text())[1] 
                            with sql:column("S.Value")')
  from GDB_ITEMS as T
    cross apply (select TargetNode, SourceNode from @Map where ID = @ID) as M
    cross apply (select Documentation.value('(//GeoBndBox/*[local-name(.)=sql:column("M.SourceNode")])[1]', 'varchar(20)')) as S(Value)

  set @ID += 1
end  

Попробуйте здесь: http://data.stackexchange.com/stackoverflow/query/59329/new

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...