SQL Server 2008 XML обновление во фрагменте? U - PullRequest
1 голос
/ 10 июня 2011

У меня есть таблица SQL Server 2008 с 50k строк, каждая с фрагментом XML в столбце varchar, который выглядит следующим образом:

<infoElems>
        <infoElem id="1" Name="somename" money="3399.3984939" />
</infoElems>

Мне нужно выбрать столбец varcharвыберите атрибут money, замените его на фактический тип денег (3399,40 в моем примере), а затем верните весь фрагмент обратно.

Может кто-нибудь указать, как мне пройти через это?Я думаю, что мне нужно создать какой-то индекс XML?Смущен.

Спасибо.

Ответы [ 3 ]

2 голосов
/ 11 июня 2011
-- Table with xml fragment
declare @YourTable table(SomeID int identity, YourColumn varchar(max))

-- Add 2 rows of test data
insert into @YourTable values(
'<infoElems>
        <infoElem id="1" Name="somename" money="3399.3984939" />
</infoElems>')

insert into @YourTable values(
'<infoElems>
        <infoElem id="1" Name="somename" money="4399.3584939" />
</infoElems>')

-- Declare a table variable with a xml column
declare @TempTable table(SomeID int, YourColumn xml)

-- Copy rows that should be modified (ID and xml is enough)
insert into @TempTable
select SomeID, YourColumn
from @YourTable

--Modify the money attribute in TempTable
;with cte as
(
  select YourColumn.value('(infoElems/infoElem/@money)[1]', 'money') as MoneyCol,
         YourColumn
  from @TempTable
)
update cte set
  YourColumn.modify('replace value of (infoElems/infoElem/@money)[1] with sql:column("MoneyCol")')  

-- Write the changes back to the source table
update Y set
  Y.YourColumn = cast(T.YourColumn as varchar(max))
from @YourTable as Y
  inner join @TempTable as T
    on Y.SomeID = T.SomeID

-- Look at the result  
select *
from @YourTable  

Результат:

SomeID  YourColumn
------  ---------------------------------------------------------------------------
1       <infoElems><infoElem id="1" Name="somename" money="3399.3985"/></infoElems>
2       <infoElems><infoElem id="1" Name="somename" money="4399.3585"/></infoElems>

Деньги в SQL Server имеют 4 знака после запятой. Если вы хотите 2 десятичных знака, вы должны использовать вместо этого этот оператор обновления.

--Modify the money attribute in TempTable
;with cte as
(
  select YourColumn.value('(infoElems/infoElem/@money)[1]', 'numeric(15,2)') as MoneyCol,
         YourColumn
  from @TempTable
)
update cte set
  YourColumn.modify('replace value of (infoElems/infoElem/@money)[1] with sql:column("MoneyCol")')  
1 голос
/ 10 июня 2011

Типы данных делают это уродливым, особенно если XML в ваших столбцах отличается от цены. Вот что будет работать в SQL 2008. Если вам нужно обновить много строк, вам придется использовать это с CURSOR.

DECLARE @orig VARCHAR(20), @new money
DECLARE @origXml XML, @newXml VARCHAR(100)

// first you have to cast to xml
SELECT @origXml = CAST(myColunm AS XML) 
FROM dbo.Tbl1
WHERE ...

// then extract the value as a string
SET @orig = @origXml.value('(//infoElem/@money)[1]','varchar(20)') 

// then get the new value to the right percision - MONEY is accurate to the ten-thousandth hence the ROUND
SET @new = ROUND(CAST(@orig AS MONEY),2)  

SET @newXml = REPLACE(CAST(@origXml AS VARCHAR(100)),  
  'money="'+CAST(@orig AS VARCHAR)+'"',
  'money="'+CAST(@new AS VARCHAR)+'"') // then replace - this can be combined with the update 

UPDATE dbo.Tbl1 SET myColunm = @newXml // then update

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

1 голос
/ 10 июня 2011

В принципе, вы можете сделать что-то вроде этого:

SELECT
   SomeID,
   CAST(YourColumn AS XML).value('(/infoElems/infoElem/@money)[1]', 'money') AS 'MoneyValue'
FROM 
   dbo.YourTable
WHERE
   ....

для получения списка ваших строк и атрибута money из вашего XML.

Было бы намного проще, если бы этот столбец - содержащий только XML - на самом деле был бы типа XML .... вы могли бы спасти себя CAST(....AS XML)

...