Xml.modify里面的SQL REPLACE函数'替换值'

时间:2017-11-01 05:18:22

标签: sql-server xml xpath

我正在尝试更新SQL Server中的一些XML数据。 XML包含如下所示的数据:

<root>
    <id>1</id>
    <timestamp>16-10-2017 19:24:55</timestamp>
</root>

假设此XML存在于名为Data的表中名为TestTable的列中。 我希望能够更改时间戳中的连字符以转发斜杠。

我希望自己可以做类似的事情:

update TestTable
set Data.modify('replace value of 
(/root/timestamp/text())[1] with REPLACE((/root/timestamp/text())[1], "-", "/")')

我收到以下错误:

  

XQuery [TestTable]:没有函数“{http://www.w3.org/2004/07/xpath-functions}:REPLACE()'

当我考虑它时,这是有道理的。但我想知道,有没有办法在单个更新语句中执行此操作?或者我首先需要查询时间戳值并将其保存为变量,然后使用变量更新XML?

4 个答案:

答案 0 :(得分:1)

如果没有外部需要你需要填写,你应该在XML中使用ISO8601日期/时间字符串。

您的dateTime-string与文化相关。在具有不同语言或日期格式设置的不同系统上阅读此内容将导致错误或 - 更糟糕!!! - 导致错误结果。

“08-10-2017”之类的日期可以是10月8日或8月10日......

最糟糕的是,这可能会成功通过所有测试,但会在客户的计算机上出现奇怪的错误消息或结果不佳导致实际数据损坏!

将连字符切换为斜线只是装饰性的! XML是严格定义的数据容器。任何非字符串数据都必须表示为安全的可转换字符串。

这是你应该做的:

DECLARE @tbl TABLE(ID INT IDENTITY,YourXML XML);
INSERT INTO @tbl VALUES
(N'<root>
    <id>1</id>
    <timestamp>16-10-2017 19:24:55</timestamp>
</root>');

UPDATE @tbl SET YourXml.modify(N'replace value of (/root/timestamp/text())[1] 
                                 with concat(  substring((/root/timestamp/text())[1],7,4), "-"
                                              ,substring((/root/timestamp/text())[1],4,2), "-"
                                              ,substring((/root/timestamp/text())[1],1,2), "T"
                                              ,substring((/root/timestamp/text())[1],12,8)
                                            ) cast as xs:dateTime?');

SELECT * FROM @tbl;

结果

<root>
  <id>1</id>
  <timestamp>2017-10-16T19:24:55</timestamp>
</root>

答案 1 :(得分:1)

您还可以通过联接到内联视图并使用SQL REPLACE函数来做到这一点:

   CREATE TABLE TestTable
   (    
       Id INT IDENTITY(1,1) NOT NULL,
       Data XML NOT NULL
   )

   INSERT TestTable (Data) VALUES ('<root>
        <id>1</id>
        <timestamp>16-10-2017 19:24:55</timestamp>
    </root>')

    UPDATE TestTable
    SET Data.modify('replace value of 
    (/root/timestamp/text())[1] with sql:column("T2.NewData")')
    FROM TestTable T1
    INNER JOIN (
        SELECT Id
        , REPLACE( Data.value('(/root/timestamp/text())[1]', 'nvarchar(max)'), '-', '/') AS NewData
        FROM TestTable
    ) T2
    ON T1.Id = T2.Id

    SELECT * FROM TestTable

答案 2 :(得分:0)

您可以尝试使用下面的字符串替换

update testtable 
set data= cast(
concat(
    left(cast(data as varchar(max)),charindex('<timestamp>',cast(data as varchar(max)))+len('<timestamp>')-1),
    replace(
        substring(
                    cast(data as varchar(max)),
                    len('<timestamp>')   + 
                        charindex( '<timestamp>', cast(data as varchar(max))) ,
                    charindex('</timestamp>',cast(data as varchar(max)))
                        -charindex('<timestamp>',cast(data as varchar(max)))
                        -len('<timestamp>')
                 ),
        '-','/'),
    right(cast(data as varchar(max)),len(cast(data as varchar(max)))-charindex('</timestamp>',cast(data as varchar(max)))+1)
       ) as xml)

select * 
from testtable

working demo

答案 3 :(得分:0)

注意:此答案假定您希望将此格式设置为将其显示为字符串,而不是将内容解析为xs:dateTime。如果您想要后者,Shungo的答案将按其格式化。

在撰写本文时,replace似乎不是supported XQuery function in SQL Server。您可以在substring中使用concat函数和"replace value of (XML DML)"函数。

CREATE TABLE #t(x XML);
INSERT INTO #t(x)VALUES(N'<root><id>1</id><timestamp>16-10-2017 19:24:55</timestamp></root>');

UPDATE
    #t
SET
    x.modify('replace value of (/root/timestamp/text())[1]
              with concat(substring((/root/timestamp/text())[1],1,2),
                          "/",
                          substring((/root/timestamp/text())[1],4,2),
                          "/",
                          substring((/root/timestamp/text())[1],7)
                         ) ') 

SELECT*FROM #t;

作出结果:

<root><id>1</id><timestamp>16/10/2017 19:24:55</timestamp></root>