sql-server - Msg 9402, Level 16, State 1, Line 9 XML解析: line 1,字符38,无法切换编码

标签 sql-server xml tsql casting character-encoding

一段 tsql 代码从生产环境到测试环境的行为不同。当下面的代码在 prod 上执行时,它会带回数据

SELECT [col1xml]

FROM [DBName].[dbo].[Table1] (NOLOCK)

WHERE (cast([col1xml] as xml).value('(/Payment/****/trn1)[1]','nvarchar(20)') ='123456'))

但是,在测试中运行时,相同的代码会带回以下错误。

Msg 9402, Level 16, State 1, Line 9 XML parsing: line 1, character 38, unable to switch the encoding



我已经看到了这个 UTF 转换站点提供的修复程序,这在生产和测试中都有效。见下文。但是,我需要向开发人员提供为什么会发生这种行为的答案以及他们应该更改代码的理由(如果是这种情况)
WHERE CAST(

REPLACE(CAST(col1xml AS VARCHAR(MAX)), 'encoding="utf-16"', 'encoding="utf-8"')

AS XML).value('(/Payment/****/trn1)[1]','NVARCHAR(max)') ='123456')

我已经比较了两个数据库并寻找任何明显的东西,例如 ansi nulls 和 ansi padding。一切都和 SQL Server 的版本相同。这是 SQL SERVER 2012 11.0.5388 版本。环境之间的数据不同,但表架构相同,col1xml 的数据类型为 ntext。

最佳答案

在 SQL Server 中,您应该将 XML 存储在类型为 XML 的列中。 .这种原生类型有很多优点。是快得多并具有隐式有效性检查。
从我提出的问题来看,您将 XML 存储在 NTEXT 中.这种类型是已弃用 百年与将不支持 在 future 的版本中! 你应该尽快改变这一点!
SQL-Server 知道两种字符串:

  • 1 字节字符串( CHARVARCHAR ),这是扩展的 ASCII
    重要提示:这不是UTF-8! native UTF-8 支持将成为即将推出的版本的一部分。
  • 2 字节字符串( NCHARNVARCHAR ),即 UTF-16 (UCS-2)

  • 如果 XML 有一个带编码的前导声明(在大多数情况下,这是 utf-8utf-16),您可能会遇到麻烦。
    如果 XML 存储为 2 字节字符串(至少 NTEXT 告诉我这一点),声明 必须是 utf-16 .对于 1 字节的字符串,它应该是 utf-8 .
    最好的(也是最简单的)是完全省略声明。你不需要它。以适当的类型存储 XML 将自动终止此声明。
    您应该做什么:创建一个类型为 XML 的新列并将您所有的 XML 洗牌到此列。摆脱任何 TEXT , NTEXTIMAGE您可能拥有的列!
    下一步是:快乐并享受原生 XML 类型的快速和轻松:-D
    UPDATE 环境差异
    你写:环境之间的数据是不同的
    错误发生在这里:
    cast([col1xml] as xml)
    
    如果您的列将以 native 类型存储 XML,则根本不需要强制转换(这是 非常昂贵!! )。但是在您的情况下,此转换取决于实际的 XML。因为它存储在 NTEXT它是 2 字节字符串。如果您的 XML 以声明不支持的编码(在大多数情况下 utf-8 )开头,这将失败。
    尝试这个:
    这有效
    DECLARE @xml2Byte_UTF16 NVARCHAR(100)='<?xml version="1.0" encoding="utf-16"?><root>test1</root>';
    SELECT CAST(@xml2Byte_UTF16 AS XML);
    
    DECLARE @xml1Byte_UTF8 VARCHAR(100)='<?xml version="1.0" encoding="utf-8"?><root>test2</root>';
    SELECT CAST(@xml1Byte_UTF8 AS XML);
    
    这失败了
    DECLARE @xml2Byte_UTF8 NVARCHAR(100)='<?xml version="1.0" encoding="utf-8"?><root>test3</root>';
    SELECT CAST(@xml2Byte_UTF8 AS XML);
    
    DECLARE @xml1Byte_UTF16 VARCHAR(100)='<?xml version="1.0" encoding="utf-16"?><root>test4</root>';
    SELECT CAST(@xml1Byte_UTF16 AS XML);
    
    玩转 VARCHARNVARCHARutf-8utf-16 ...

    关于sql-server - Msg 9402, Level 16, State 1, Line 9 XML解析: line 1,字符38,无法切换编码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44892059/

    相关文章:

    sql-server - TSQL代数-求解x((a)x <b)

    java - 在同一个Android Studio页面中显示两个listView

    xml - Xpath:简单条件检查并在 Xpath 表达式中赋值

    sql - 为每一行插入一系列值的最简洁方法?

    sql-server - SQL Server 存储过程需要未提供的参数

    SQL素数函数

    sql-server - 日志文件随着简单恢复模式而增长

    SQL Server 2012 列标识增量在第 7 个条目上从 6 跳到 1000+

    xml - 在 XSLT 中省略数字

    sql - 为什么分解这个相关子查询 vaSTLy 可以提高性能?