FOR XML无法序列化数据,因为它包含字符(0x0000)


18

我有一个大查询(如有必要,我将在此处发布),并且出现此错误:

消息6841,级别16,状态1,第1行
FOR XML无法序列化节点'NoName'的数据,因为它包含XML不允许的字符(0x0000)。要使用FOR XML检索此数据,请将其转换为二进制,varbinary或图像数据类型,然后使用BINARY BASE64指令。

我使用的唯一部分FOR XML是在这里:

WHERE 
    (CodFuncionario = Results.CodFuncionario) 
FOR XML PATH(''), TYPE).value('(./text())[1]', 
    'VARCHAR(MAX)'), 1, 2, '') AS [Experiencia]

但是,什么是node noname?以及如何寻找该值:(0x0000)

这是子查询之一(我只有FOR XML):

SELECT 
    [CodFuncionario],
    STUFF
    (
        (
            SELECT 
                ' / ' + 
            CAST
            (
                [DescFuncao] + '-' + 
                [DescTempoExperiencia] 
                AS VARCHAR(MAX)
            )...
FROM 
    [Linked_Server].db.dbo.tblFuncionarioExperiencia T0
INNER JOIN
    [Linked_Server].db.dbo.tblFuncao T1 On T0.codFuncao = T1.CodFuncao
INNER JOIN
    [Linked_Server].db.dbo.tblTempoExperiencia T2 ON T0.CodTempoExperiencia = T2.CodTempoExperiencia 
WHERE 
   (CodFuncionario = Results.CodFuncionario) 
   FOR XML PATH(''), TYPE).value('(./text())[1]', 'VARCHAR(MAX)'), 1, 2, '') AS [Experiencia]
  FROM 
      [Linked_Server].db.dbo.tblFuncionarioExperiencia Results  
  GROUP BY 
      CodFuncionario) as T2

  On T0.CodFuncionario = T2.CodFuncionario

Left Join...

Answers:


10

该行:

...
SELECT 
    [CodFuncionario],
    STUFF
    (
        (
            SELECT 
                ' / ' + 
                CAST
                (
                    [DescFuncao] + '-' + 
                    [DescTempoExperiencia] 
                    AS VARCHAR(MAX)
                )...

应该:

...
SELECT 
    [CodFuncionario],
    STUFF
    (
        (
            SELECT 
                ' / ' + 
                CAST
                (
                    replace -- *** NEW! ***
                    (
                        [DescFuncao] + '-' + 
                        [DescTempoExperiencia],
                        char(0),
                        ''
                    ) 
                    AS VARCHAR(MAX)
                )...

11

当我这样做时,我得到相同的错误:

DECLARE @foo VARCHAR(32) = CHAR(0); -- 0x0000
SELECT @foo FOR XML PATH, TYPE;

因此,找到DescFuncaoor的所有实例DescTempoExperiencia(对不起,您不使用表别名,因此无法确定它们来自哪个表)内容所包含的位置CHAR(0)并进行修复。例如:

UPDATE dbo.whatever 
  SET DescFuncao = REPLACE(DescFuncao, CHAR(0), '')
  WHERE DescFuncao LIKE '%' + CHAR(0) + '%';

仅过滤查询中的那些行是不够的,因为您不知道XML方法将在什么时候起作用,但是您也可以尝试:

STUFF(( SELECT ' / ' + CAST(REPLACE([DescFuncao] + '-' 
  + [DescTempoExperiencia], CHAR(0), '') AS VARCHAR(MAX))

当然,一次修复源数据比每次运行这些替换例程要高效得多。

请注意,这可能不是导致此问题的唯一特定字符。0x0001-> 0x0008也将产生相同的错误。因此,如果您在那里也有这些字符,则应调查它们的来源,并修复源。


1
带有大量表情符号的数据该怎么办?
devinbost

10

我使用ASCII字符0-255对此进行了测试,发现您遇到以下字符错误:0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x000B, 0x000C, 0x000E, 0x000F, 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F

一种解决方法是, TYPE从XML语句中删除。

另一种方法是在select语句中删除那些字符:

REPLACE( REPLACE( REPLACE( REPLACE( REPLACE( 
REPLACE( REPLACE( REPLACE( REPLACE( REPLACE( 
REPLACE( REPLACE( REPLACE( REPLACE( REPLACE( 
REPLACE( REPLACE( REPLACE( REPLACE( REPLACE( 
REPLACE( REPLACE( REPLACE( REPLACE( REPLACE( 
REPLACE( REPLACE( REPLACE( REPLACE( 
    < YOUR EXPRESSION TO BE CLEANED >
,char(0x0000),'') ,char(0x0001),'') ,char(0x0002),'') ,char(0x0003),'') ,char(0x0004),'') 
,char(0x0005),'') ,char(0x0006),'') ,char(0x0007),'') ,char(0x0008),'') ,char(0x000B),'') 
,char(0x000C),'') ,char(0x000E),'') ,char(0x000F),'') ,char(0x0010),'') ,char(0x0011),'') 
,char(0x0012),'') ,char(0x0013),'') ,char(0x0014),'') ,char(0x0015),'') ,char(0x0016),'') 
,char(0x0017),'') ,char(0x0018),'') ,char(0x0019),'') ,char(0x001A),'') ,char(0x001B),'') 
,char(0x001C),'') ,char(0x001D),'') ,char(0x001E),'') ,char(0x001F),'')

您还可以使用这些replace语句创建一个函数。


这个解决方法的想法帮助我找到了一个大型复杂的公用表表达式中的哪个xml块因此错误而失败。
基思·约翰·哈奇森

2
这个脚本很有用(虽然很慢),但是对表情符号字符(例如0xD83D)不起作用,我怀疑其中可能有很多……至少在我的数据中。:'(或者我应该说:0x1F62D
devinbost

1

通过使用translate()优化@jumxozizi的答案(SQL Server 2017 ++)。下面的代码将这些字符替换为句点。

declare
    @illegalChars nvarchar(4000) = 
        char(0) + char(1) + char(2) + char(3) + char(4) + char(5) + char(6) + char(7) + char(8) + char(11) + 
        char(12) + char(14) + char(15) + char(16) + char(17) + char(18) + char(19) + char(20) + char(21) + char(22) + 
        char(23) + char(24) + char(25) + char(26) + char(27) + char(28) + char(29) + char(30) + char(31);

select translate(input, @illegalChars, replicate('.', len(@illegalChars))) as Result

要剥离它们,可以先将它们转换为char(0),然后用replace()包装。

从想法上看:https : //stackoverflow.com/a/55906638/538763

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.