我有一个存储在SQL Server表xml列中的xml文档,该日期字段中的时间不准确
我想将文档中的所有日期和时间(SaleDateTime,LineStartTime,LineEndTime)值更新15秒,例如,2012-02-01T00:07:50成为2012-02-01T00:08 :05(关于为什么它需要这样的长篇故事;它不在我的手中)。可以有1到多个事务,每个事务可以有1个或多个行条目。
我已经尝试过使用DATEADD的OPENXML,修改方法等,但我无法做到正确。我没办法。任何帮助表示赞赏。在此先感谢!!
示例在
之下CREATE TABLE XMLTable (doc xml);
INSERT INTO XMLTable (doc)
VALUES
(
'<?xml version="1.0" encoding="UTF-8"?>
<Root>
<Transaction>
<SaleID>1</SaleID>
<Sale>
<SaleDateTime>2012-02-01T00:07:00</SaleDateTime>
<LineItem>
<Line>1</Line>
<LineStartTime>2012-02-01T00:07:00</LineStartTime>
<LineEndTime>2012-02-01T00:07:00</LineEndTime>
<Amount>13.50</Amount>
</LineItem>
</Sale>
</Transaction>
<Transaction>
<SaleID>2</SaleID>
<Sale>
<SaleDateTime>2012-02-01T00:11:00</SaleDateTime>
<LineItem>
<Line>1</Line>
<LineStartTime>2012-02-01T00:11:00</LineStartTime>
<LineEndTime>2012-02-01T00:11:00</LineEndTime>
<Amount>13.50</Amount>
</LineItem>
<LineItem>
<Line>2</Line>
<LineStartTime>2012-02-01T00:11:00</LineStartTime>
<LineEndTime>2012-02-01T00:11:00</LineEndTime>
<Amount>5.22</Amount>
</LineItem>
</Sale>
</Transaction>
</Root>')
SELECT * FROM XMLTable
答案 0 :(得分:1)
您可以使用modify
方法。例如,替换第一次出现的SaleDateTime
:
declare @now datetime = getdate()
update XMLTable
set doc.modify('replace value of (/Root/Transaction/Sale/SaleDateTime/text())[1]
with sql:variable("@now")')
答案 1 :(得分:1)
如果您知道XML文档的结构,最快的选择可能是将文档分解为使用for xml
重建文档。此解决方案还可以轻松修改,以便一次性跨表中的多行进行转换,而不是一次处理一个文档。
对于问题中给出的结构,对XML变量的查询将如下所示。
select T.X.value('(SaleID/text())[1]', 'int') as SaleID,
(
select dateadd(second, 15, S.X.value('(SaleDateTime/text())[1]', 'datetime')) as SaleDateTime,
(
select L.X.value('(Line/text())[1]', 'int') as Line,
dateadd(second, 15, L.X.value('(LineStartTime/text())[1]', 'datetime')) as LineStartTime,
dateadd(second, 15, L.X.value('(LineEndTime/text())[1]', 'datetime')) as LineEndTime,
L.X.value('(Amount/text())[1]', 'varchar(20)') as Amount
from S.X.nodes('LineItem') as L(X)
for xml path('LineItem'), type
)
from T.X.nodes('Sale') as S(X)
for xml path('Sale'), type
)
from @doc.nodes('/Root/Transaction') as T(X)
for xml path('Transaction'), root('Root'), type
正如我所说,可以修改它以反对表,甚至可以更改为更新XML列。
答案 2 :(得分:0)
如果这些XML文档不是很大,或者这是一次性事情并且性能不是优先级,则可以将文档转换为varchar并对其执行REPLACE
以增加日期。
下面是一个例子(你可以将它包装在一个函数中):
declare @doc xml =
'<?xml version="1.0" encoding="UTF-8"?>
<Root>
<Transaction>
<SaleID>1</SaleID>
<Sale>
<SaleDateTime>2012-02-01T00:07:00</SaleDateTime>
<LineItem>
<Line>1</Line>
<LineStartTime>2012-02-01T00:07:00</LineStartTime>
<LineEndTime>2012-02-01T00:07:00</LineEndTime>
<Amount>13.50</Amount>
</LineItem>
</Sale>
</Transaction>
<Transaction>
<SaleID>2</SaleID>
<Sale>
<SaleDateTime>2012-02-01T00:11:00</SaleDateTime>
<LineItem>
<Line>1</Line>
<LineStartTime>2012-02-01T00:11:00</LineStartTime>
<LineEndTime>2012-02-01T00:11:00</LineEndTime>
<Amount>13.50</Amount>
</LineItem>
<LineItem>
<Line>2</Line>
<LineStartTime>2012-02-01T00:11:00</LineStartTime>
<LineEndTime>2012-02-01T00:11:00</LineEndTime>
<Amount>5.22</Amount>
</LineItem>
</Sale>
</Transaction>
</Root>'
declare @New xml = @doc;
;with
dates (LineStartTime, LineEndTime) as
( -- get the start/end dates in any LineItem
select p.n.value('(LineStartTime)[1]', 'datetime'),
p.n.value('(LineEndTime)[1]', 'datetime')
from @doc.nodes('Root/Transaction/Sale/LineItem')p(n)
),
upd (OldValue, NewValue) as
( -- add 15 min to each, and cast as varchar
select '<LineStartTime>' + convert(varchar, LineStartTime, 126) + '</LineStartTime>',
'<LineStartTime>' + convert(varchar, dateadd(mi, 15, LineStartTime), 126) + '</LineStartTime>'
from dates
union
select '<LineEndTime>' + convert(varchar, LineEndTime, 126) + '</LineEndTime>',
'<LineEndTime>' + convert(varchar, dateadd(mi, 15, LineEndTime), 126) + '</LineEndTime>'
from dates
)
-- cast @doc as varchar, and replace each occurrence of start/end elements with NewValue
select @new = cast(replace(cast(@new as varchar(max)), OldValue, NewValue) as xml)
from upd;
select [Old]=@doc, [New]=@new;