Quando si converte SQL dinamico (query pivot) in output xml, perché la prima cifra della data viene convertita in unicode?


11

Sto usando questo fantastico esempio /dba//a/25818/113298 di Bluefeet, per creare un perno e trasformarlo in dati XML.

Dichiarando il param

DECLARE @cols AS NVARCHAR(MAX),  @query  AS NVARCHAR(MAX);

Successivamente c'è un CTE con molto codice, l'endresult del CTE viene inserito in un DB temporaneo (come nell'esempio)

SELECT 
B.[StayDate] -- this is a date dd-mm-yyyy
, B.[Guid]
INTO #tempDates
FROM BaseSelection B

Generare i col (come nell'esempio)

SELECT @cols = STUFF((SELECT distinct ',' +QUOTENAME(convert(char(10), [StayDate] , 120)) 
FROM #tempDates
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)') 
,1,1,'');

Il set di risultati è quello che dovrei aspettarmi

set @query = 
   'SELECT [Guid],' + @cols +'
    FROM
    (
        SELECT 
            [StayDate] 
           ,[Guid]
        FROM #tempDates
    ) A
    pivot
    (
        count([StayDate])
        for [StayDate] in (' + @cols +')                    
    ) p
    '
EXEC sp_executesql  @query ;

inserisci qui la descrizione dell'immagine

Quando provo a trasformarlo in XML, i miei attributi vengono convertiti solo parzialmente

set @query = 
   'SELECT [Guid],' + @cols +'
    FROM
    (
        SELECT 
            [StayDate] 
           ,[Guid]
        FROM #tempDates
    ) A
    pivot
    (
        count([StayDate])
        for [StayDate] in (' + @cols +')                    
    ) p
    for xml auto
    -- when using for XML path i will get a error
    -- FOR XML PATH(''''), ROOT(''root'') 
    -- Msg 6850, Level 16, State 1, Line 3
    -- Column name '2016-12-17' contains an invalid XML identifier 
    -- as required by FOR XML; '2'(0x0032) is the first character at fault.
    '
EXEC sp_executesql  @query ;

di risultati

<p Guid="3C3359E3-CFE5-E511-80CA-005056A90901"
  _x0032_016-12-17="2" --> should be 2016-12-17="2" 
  _x0032_016-12-18="2" --> should be 2016-12-18="2" 
  _x0032_016-12-19="2" --> should be 2016-12-19="2" 
/>

Ho perso qualcosa, perché solo una parte della data viene convertita in Unicode?

Come posso risolvere questo problema?


Per quale versione di SQL Server si tratta?
ypercubeᵀᴹ

SQL Server 2012, ma non è questo il punto, sono le specifiche
dell'xml

Sembra un problema XY. L'uso di una data come nome di attributo in XML sembra sconsigliato anche se funzionava come previsto. Sarei più propenso a memorizzare la data come valore di un attributo o forse come testo di un elemento, a seconda di ciò che avevo pianificato di fare con esso. Se necessario, creerei più elementi con coppie di attributi.
jpmc26,

Risposte:


14

I nomi degli attributi in XML non possono iniziare con un numero, vedere NameStartChar .

Devi trovare nomi alternativi per i tuoi attributi e codificarli in una @colsvariabile separata specificando gli alias di colonna per la tua query pivot dinamica.

SELECT @cols2 = STUFF((SELECT distinct ',' +
                       quotename(convert(char(10), [StayDate] , 120)) + 
                       ' as '+ QUOTENAME('z'+convert(char(10), [StayDate] , 120)) 
FROM #tempDates
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)') 
,1,1,'');

Risultato;

[2016-12-20] as [z2016-12-20],[2016-12-21] as [z2016-12-21]
<p Guid="6365FC57-F476-4703-B9D4-1EB81288FF30" z2016-12-20="0" z2016-12-21="1" />
<p Guid="B38FA9DB-B4E1-4725-8F3B-3AF6E009C10A" z2016-12-20="1" z2016-12-21="0" />

Quando si utilizza for xml autoSQL Server lo fa per te.


Quello era il collegamento mancante, anche per il percorso xml (''), root ('root') ora funziona.
Bunkerbuster,

6

Il primo personaggio non è Unicode, di per sé. Voglio dire, tecnicamente tutti i caratteri in XML all'interno di SQL Server sono codificati come UTF-16 Little Endian, quindi in questo senso sono tutti Unicode. Ma quello che stai vedendo è solo la notazione di escape per un personaggio, in questo caso "2", che ha un valore esadecimale / binario di "32".

Il problema è semplicemente che i nomi XML non possono iniziare con un numero. I seguenti test mostrano che un nome di attributo o un elemento che inizia con un numero ottiene un errore, ma che inizia con un trattino basso ( _) o una lettera va bene.

SELECT CONVERT(XML, N'<test><row 2016-12-17="2" /></test>');
/*
Msg 9455, Level 16, State 1, Line 10
XML parsing: line 1, character 12, illegal qualified name character
*/


SELECT CONVERT(XML, N'<test><2016>a</2016></test>');
/*
Msg 9455, Level 16, State 1, Line 10
XML parsing: line 1, character 8, illegal qualified name character
*/


SELECT CONVERT(XML, N'<test><row _2016-12-17="2" /></test>');
/*
<test>
  <row _2016-12-17="2" />
</test>
*/


SELECT CONVERT(XML, N'<test><row x2016-12-17="2" /></test>');
/*
<test>
  <row x2016-12-17="2" />
</test>
*/

Pertanto, è necessario aggiungere un prefisso ai nomi delle colonne con un carattere valido come carattere iniziale per un attributo XML o un nome di elemento.


Inoltre, sei sicuro che stia "lavorando" con FOR XML AUTO? Da quello che posso vedere, sta semplicemente convertendo automaticamente il carattere "non valido" in _x0032_:

SELECT tmp.* FROM (SELECT 2) tmp([2016]) FOR XML AUTO;

Ritorna:

<tmp _x0032_016="2" />
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.