从先前转换为 XML 的 table 列中提取多个值

Extracting multiple values from a table column previously casted to XML

我有一个 table 列作为 nvarchar(max),其中包含以下 XML 数据:

<?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>

我想 SELECT 'ContextName' 和 'EnumValueName' XML 元素的串联。

起初我只是尝试 return 一个元素,效果很好:

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

因为我不想在查询中转换两次,所以我正在寻找一种方法将 XML 列从此处解构为 table 和 select 列。到目前为止,我遇到了以下无效查询:

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()]: 'value()' requires a singleton (or empty sequence), found operand of type '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


已将 ntext 替换为 nvarchar(max) ;)

你已经被告知,NTEXT 几个世纪以来一直被弃用 ;-)

只是一些背景:

NTEXT2 字节 编码的文本,将转换为 NVARCHAR。但是你的 XML 大喊 我是 UTF-8!!!!,这是一个明显的谎言。在 NTEXT 之内 - 当然! - 不是 UTF-8。有两种方法可以继续:

  • 将您的 NTEXT 转换为 NVARCHAR,然后转换为 VARCHAR,最后转换为 XML。这将起作用,因为 UTF-8 在纯拉丁语中是 1 字节编码
  • 通过将 utf-8 替换为 1) 什么都没有(像你一样)、2) utf-16 或 3) ucs-2(正确的东西)来消除谎言。

关于您的查询:这可以做得更简单一些,因为没有重复的内容,因此不需要派生 table。试试这个:

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);