我需要使用与此类似的模式来挖掘日志表:
CREATE TABLE t (
id int PRIMARY KEY,
data varchar(max)
);
Columndata
以这种格式存储从 Web 服务接收到的 XML 文本:
这是精简版
<?xml version="1.0" encoding="UTF-8"?>
<PARAM>
<TAB DIM="30" ID="ZC3D2_1" SIZE="5">
<LIN NUM = "1">
<FLD NAME = "ZDOC" TYPE = "Char">Ferran López</FLD>
</LIN>
</TAB>
</PARAM>
当我尝试将此文本转换为 XML 时,出现下一个错误:
XML解析:第xx行,字符48,非法xml字符
可以通过删除<xml>
标签或至少删除encoding
属性来解决。
注意:如果没有特殊字符
ó
,即使我不删除<xml>
标签,它也可以正常工作。
问题
有没有办法在不替换或删除<xml>
标签的情况下将其转换为 XML?
CAST(REPLACE(data, 'encoding="UTF-8"', '') as XML)
db<>在这里摆弄
更新
服务器排序规则为:Latin1_General_BIN
但即使我尝试将排序规则更改为我通常的服务器排序规则,它也不起作用。
SELECT
id,
CAST((data COLLATE Latin1_General_CI_AS) as XML)
FROM
t;
您存储在 varchar(max) 列中的 XML 应如下所示。
应该用
ó
双字节值表示ó
。如果您的列中没有存储 UTF-8 编码的字符串,正确的方法是在将值转换为 XML 数据类型之前从 XML 中删除编码。
我认为你有一个更深层次的问题。UTF-8 允许比 SQL Server 中的常规非 Unicode 排序规则更多的字符。因此,为了安全起见,您应该使用具有 UTF-8 排序规则的 SQL Server 2019(如果由于多种原因这不可行/不可取),操作系统使用(尝试)nvarchar 而不是 varchar。
如果您害怕从 varchar 到 nvarchar 的存储增加,您可以使用行压缩。但这需要 SQL Server 2016 之前的企业版。
这里发生的是:
XML
类型在内部将数据存储为 UTF-16 Little Endian(至少在大多数情况下)。源编码是什么并不重要,最终结果将是 UTF-16 LE(并且没有<xml>
标签,因此没有encoding="..."
)。XML
:NVARCHAR
数据假定为 UTF-16 LE。如果有<xml>
标签并且它包含该encoding
属性,则唯一有效的值为"UTF-16"
.VARCHAR
当没有<xml>
标签时,或者如果标签存在但没有encoding
属性,则假定数据位于与数据的整理相关联的 8 位代码页中。否则,数据将被解释为在encoding
属性中指定的代码页中编码(即使它是在与数据整理相关的代码页中编码的)。Latin1_General_BIN
,所以它是安全的- 足以假设该列正在使用相同的排序规则)。ó
代码页 Windows-1252 中字符的代码点是: 0xF3。<xml>
标记声明 XML 数据被编码为 UTF-8。p
,其值为0x70。因此,您会收到“非法 xml 字符”错误(因为encoding="UTF-8"
告诉转换函数字节是有效的 UTF-8 字节;转换看不到ó
字符)。您的选择是:
理想情况下,列将被转换为
XML
并且标签的encoding
属性<xml>
或整个<xml>
标签本身将在进入的过程中被删除。并且,如果在创建一个重复的元素和/或属性名称时,XML
数据类型可以节省空间内部名称的字典(查找列表)并使用 ID 值记录结构。将
[data]
列设置为使用 UTF-8 排序规则(SQL Server 2019 中的新功能,因此不适合您)将
[data]
列设置为NVARCHAR
,并删除标签的encoding
属性<xml>
,或整个<xml>
标签。将传入的字符串转换为 UTF-8 字节。所以这个
ó
字符是 UTF-8 中的两个字节:0xC3B3,ó
在 Windows-1252 中出现。笔记:
encoding
属性<xml>
,或整个<xml>
标签,不是一种选择。当然,它会在这种特殊情况下工作,但它不会在所有情况下工作,因为 SQL Server 2014 中没有可用的列VARCHAR
和UTF-8 排序规则。因此,Windows 代码页 1252 中不可用的任何 Unicode 字符将转换为?
或??
(取决于 BMP 字符或补充字符):ó
字符在 Cyrillic 代码页上不可用。但是,有一个“最佳拟合”映射,这就是我们最终得到 ao
而不是 a 的原因?
。_100_
级别排序规则。此外,任何使用 SQL Server 2012 或更高版本的人都应该使用以(用于补充字符)_100_
结尾的级别排序规则。_SC
最后,当在 SQL Server 2005 或更高版本上需要二进制排序规则时,请使用一个结尾_BIN2
(请参阅我的帖子了解原因)。为您的 varchar 使用兼容的排序规则
db<>在这里摆弄