FOR XML no pudo serializar los datos porque contiene caracteres (0x0000)

18

Tengo una gran consulta (si es necesario, la publicaré aquí) y recibo este error:

El mensaje 6841, Nivel 16, Estado 1, Línea 1
FOR XML no pudo serializar los datos para el nodo 'NoName' porque contiene un carácter (0x0000) que no está permitido en XML. Para recuperar estos datos usando FOR XML, conviértalos a tipo de datos binario, varbinario o de imagen y use la directiva BINARY BASE64.

La única parte que uso FOR XMLestá aquí:

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

Pero que es node noname? y cómo puedo buscar este valor:(0x0000)

Esta es una de las subconsultas (la única parte que tengo 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...
Racer SQL
fuente

Respuestas:

10

La línea:

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

Debiera ser:

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

Me sale el mismo error cuando hago esto:

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

Por lo tanto, busque todas las instancias de DescFuncaoo DescTempoExperiencia(perdón, no usa alias de tabla, por lo que es imposible saber de qué tabla provienen) dónde están los contenidos CHAR(0)y corríjalos. Por ejemplo:

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

No es suficiente filtrar esas filas en su consulta, porque no sabe en qué punto los métodos XML funcionarán, pero también puede intentar:

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

Por supuesto, arreglar los datos de origen una vez será mucho más eficiente que ejecutar estas rutinas de reemplazo cada vez .

Tenga en cuenta que este podría no ser el único carácter específico que causa este problema. 0x0001-> 0x0008también generará el mismo error. Entonces, si también tiene esos personajes allí, debe investigar de dónde provienen y corregir la fuente.

Aaron Bertrand
fuente
1
¿Qué pasa con los datos con muchos emojis?
devinbost
10

He probado esto con caracteres ASCII 0-255 y descubrí que obtiene este error de caracteres: 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.

Una solución alternativa es eliminar , TYPEde su declaración XML.

Otra forma es eliminar esos caracteres en la instrucción 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),'')

También podría crear una función con estas instrucciones de reemplazo.

jumxozizi
fuente
Esta idea alternativa me ayudó a encontrar en qué parte de una gran expresión de tabla común compleja que para el bloque xml fallaba con este error.
Keith John Hutchison
2
Este script es útil (aunque dolorosamente lento), pero no funciona en caracteres emoji (como 0xD83D), y sospecho que puede haber muchos de ellos ... al menos en mis datos. : '(O debería decir: 0x1F62D
devinbost
1

Optimizando la respuesta de @jumxozizi usando translate () (SQL Server 2017 ++). El siguiente código reemplazará esos caracteres con puntos.

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

Para eliminarlos, uno podría traducirlos () primero a char (0) y luego envolverlos con un replace ().

De la idea: /programming//a/55906638/538763

crokusek
fuente