2013-05-04 34 views
2

我有存儲在日期字段中有不準確的時間SQL Server表XML列的XML文檔修改日期字段存儲在SQL Server表

我倒要更新所有的日期和時間(SaleDateTime,LineStartTime,LineEndTime)值減去15秒,例如2012-02-01T00:07:50變爲2012-02-01T00:08:05(長篇大論爲何它需要這樣做;它不在我手中)。可以有1到多個事務,每個事務可以有1個或多個行條目。

我試過OPENXML,修改方法等與DATEADD,我不能正確的。我不知道該怎麼做。任何幫助表示讚賞。提前致謝!!

樣品低於

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 

回答

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")') 
+0

謝謝。我嘗試了修改方法,但我的問題是如何將15秒添加到每個日期時間字段? – user2349972 2013-05-04 15:00:49

+0

您必須讀取舊值然後進行設置。您必須遍歷每行和每次銷售。在C#或VB中可能更容易解決客戶端問題。 – Andomar 2013-05-04 15:04:51

+0

謝謝!你會舉一個例子嗎? – user2349972 2013-05-04 15:07:01

0

如果這些文檔不巨大的,或者這是一個一次性的事情,性能不是很重要,您可以施放該文件爲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][email protected], [New][email protected]; 
+0

哇,真酷!這可能對我有用!非常感謝你,Nathan,謝謝你Adomar! – user2349972 2013-05-05 00:00:02

+0

我試了一個大文件(24k交易),它跑了大約一個小時。它看起來像一個很好的小文檔解決方案(如你所說),但對於大文檔需要很長時間。 – user2349972 2013-05-05 00:42:40

+0

嘗試更改xpath以使其更具體,例如:'Root/Transaction/Sale/LineItem'。這可能有助於表現。我上面做了編輯。另外,文檔是否有大量的獨特日期?或者它們大部分是相同的開始和結束日期值正在增加? – 2013-05-05 01:46:53

0

如果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列。