从表列中提取多个值之前强制转换为XML

问题描述 投票:2回答:1

我有一个包含下面的XML数据的表列作为为nvarchar(最大):

<?xml version="1.0" encoding="utf-8"?>
<SerializableAlertDetail xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="SerializableContextAlertDetail">
  <ContextName>Evénements PTI mobile</ContextName>
  <EnumValueName>Pré Alerte immobilisme</EnumValueName>
</SerializableAlertDetail>

我想选择“CONTEXTNAME”和“EnumValueName” XML元素的串联。

起初我只是试图返回一个元素,它正常工作:

SELECT CAST(REPLACE(dbo.AlertDetail.Context, 'encoding="utf-8"', '') AS XML).value('(/SerializableAlertDetail/*[local-name() = "ContextName"])[1]', 'nvarchar(max)') As DisplayName FROM Table

因为我不想在查询中投两次,我正在寻找一种方式来解构XML列到一个表,然后从这里选择列。到目前为止,我坚持用下面的查询无效:

SELECT T0.XML.value('ContextName', 'nvarchar(max)')
FROM Table c
    CROSS APPLY (SELECT CAST(REPLACE(c.Context, 'encoding="utf-8"', '') AS XML)) as T(X)
    CROSS APPLY T.X.nodes('SerializableAlertDetail') AS T0(XML)

但它失败,出现以下错误信息:

的XQuery [T.X.value()]: '值()' 需要单(或空序列),实测值类型的操作数 'XDT:untypedAtomic类型*'

任何帮助表示赞赏。

编辑1


我得出以下查询工作,但可能可能不是最优的:

SELECT T0.XML.query('./ContextName').value('.', 'nvarchar(max)') + T0.XML.query('./EnumValueName').value('.', 'nvarchar(max)')
FROM Table c
        CROSS APPLY (SELECT CAST(REPLACE(c.Context, 'encoding="utf-8"', '') AS XML)) as T(X)
        CROSS APPLY T.X.nodes('SerializableAlertDetail') AS T0(XML)

编辑2


通过为nvarchar(最大)代替NTEXT;)

sql-server xml xpath sqlxml
1个回答
1
投票

你已经被告知,NTEXT已经废弃了百年;-)

只是一些背景:

NTEXT是2字节编码的文本和将转化为NVARCHAR。但是你的XML大喊大叫我是UTF-8 !!!!,这是一个普通的谎言。在NTEXT它是 - 肯定! - 不是UTF-8。有进行两种方法:

  • 投下你NTEXTNVARCHAR,然后VARCHAR最后到XML。这将工作,为UTF-8是内滑动拉丁编码1个字节。
  • 用1)没有更换utf-8(像你一样),2)utf-16或3)ucs-2(正确的事)带走的谎言。

关于您的查询:这可以简单一点,因为没有重复的内容,因此没有必要对派生表。尝试这个:

SELECT X.value('(/SerializableAlertDetail/ContextName/text())[1]','nvarchar(max)') 
     + X.value('(/SerializableAlertDetail/EnumValueName/text())[1]','nvarchar(max)')
FROM Table c
        CROSS APPLY (SELECT CAST(REPLACE(c.Context, 'encoding="utf-8"', '') AS XML)) as T(X);

这应该是快...

在可读性方面,你甚至可以尝试

SELECT X.value('(//ContextName)[1]','nvarchar(max)') 
     + X.value('(//EnumValueName)[1]','nvarchar(max)')
FROM Table c
        CROSS APPLY (SELECT CAST(REPLACE(c.Context, 'encoding="utf-8"', '') AS XML)) as T(X);
© www.soinside.com 2019 - 2024. All rights reserved.