1

我有一个包含 50k 行的 SQL Server 2008 表,每行都有一个 XML 片段,varchar列中如下所示:

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

我需要选择varchar列,选择货币属性,将其更改为实际货币类型(在我的示例中为 3399.40),然后将整个片段放回去。

谁能指出如何让我度过这个难关?我想我需要创建某种 XML 索引?使困惑。

谢谢。

4

3 回答 3

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>

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")')  
于 2011-06-10T20:34:37.537 回答
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)

于 2011-06-10T16:30:10.487 回答
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

根据您的情况,编写一个外部脚本来执行此操作可能更容易。您也可以考虑使用正则表达式 - 请参阅这篇文章,但这可能会变得非常难看。

于 2011-06-10T17:16:21.833 回答