2011-06-10 54 views
1

我有一個SQL Server 2008的表50K行,每行一個varchar列的XML片段,看起來像這樣:SQL Server 2008的XML更新ü

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

,我需要選擇出在varchar列中,選擇money屬性,將其更改爲實際的貨幣類型(在我的示例中爲3399.40),然後放回整個片段。

任何人都可以指出如何讓我通過這個?我想我需要創建某種XML索引?困惑。

謝謝。

+0

你想解決SQL Server或外部的問題嗎?您是否可以使用託管代碼(SQL Server中的.NET)或僅使用XML擴展和T-SQL? – 2011-06-10 16:08:38

回答

1

參與使這種醜陋的數據類型,特別是如果除了價格之外,您列中的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 

根據您的情況,只需編寫一個外部腳本來執行此操作可能會更容易。你也可以看看使用正則表達式 - 參見this post,但那可能會變得非常難看。

1

基本上,你可以做這樣的事情:

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

讓你行的列表,並從XML的money屬性。

這將是一個容易得多,如果該列 - 包含XML只 - 實際上XML類型的 ....你可以保存自己的CAST(....AS XML)

2
-- 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> 

Money在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")')