代码之家  ›  专栏  ›  技术社区  ›  Olivier MATROT

从以前转换为XML的表列中提取多个值

  •  2
  • Olivier MATROT  · 技术社区  · 6 年前

    我有一个名为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>
    

    我想选择“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()]:'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


    将ntext替换为nvarchar(max);)

    1 回复  |  直到 6 年前
        1
  •  1
  •   Gottfried Lesigang    6 年前

    我已经告诉过你了 NTEXT

    只是一些背景:

    内文 2字节 编码文本,并将转换为 NVARCHAR . 但是您的XML正在大喊大叫 我是UTF-8!!!! 这是一个彻头彻尾的谎言。在内部 内文 这是肯定的不是UTF-8。有两种方法可以继续:

    • 投你的 NVARCHAR ,然后 VARCHAR 最后是XML。这将起作用,就像UTF-8一样 1字节编码 在普通拉丁语中。
    • 通过替换来消除谎言 utf-8 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);