Saat mengonversi SQL dinamis (kueri pivot) ke output xml, mengapa digit pertama dari tanggal dikonversi ke unicode?

11

Saya menggunakan contoh hebat ini /dba//a/25818/113298 dari Bluefeet, untuk membuat pivot dan mengubahnya menjadi data xml.

Mendeklarasikan param

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

Berikutnya ada CTE dengan banyak kode, hasil akhir CTE dimasukkan ke dalam temp DB (sama seperti pada contoh)

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

Menghasilkan col (sama seperti contoh)

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

Set hasil adalah apa yang harus saya harapkan

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

masukkan deskripsi gambar di sini

Ketika saya mencoba mengubahnya menjadi XML, atribut saya hanya dikonversi sebagian

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 ;

resultset

<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" 
/>

Pernahkah saya melewatkan sesuatu, mengapa hanya sebagian dari tanggal yang dikonversi menjadi unicode?

Bagaimana saya bisa memperbaikinya?

Bunkerbuster
sumber
Untuk versi SQL Server apa ini?
ypercubeᵀᴹ
Sql Server 2012, tapi bukan itu intinya, itu adalah spesifikasi dari xml yang penting dalam kasus ini
Bunkerbuster
Ini sepertinya masalah XY. Menggunakan tanggal sebagai nama atribut dalam XML tampaknya tidak disarankan meskipun ini berfungsi sebagaimana mestinya. Saya akan lebih cenderung untuk menyimpan tanggal sebagai nilai atribut atau mungkin sebagai teks elemen, tergantung pada apa yang saya rencanakan untuk dilakukan dengannya. Jika perlu, saya akan membuat banyak elemen dengan pasangan atribut.
jpmc26

Jawaban:

14

Nama atribut dalam XML tidak diizinkan untuk memulai dengan angka, lihat NameStartChar .

Anda harus membuat nama alternatif untuk atribut Anda dan menyandikannya dalam @colsvariabel yang menentukan alias untuk kueri pivot dinamis Anda.

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,'');

Hasil;

[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" />

Ketika Anda menggunakan for xml autoSQL Server melakukannya untuk Anda.

Mikael Eriksson
sumber
Itu adalah tautan yang hilang, juga untuk jalur xml (''), root ('root') sekarang berfungsi.
Bunkerbuster
6

Karakter pertama bukan Unicode, per se. Maksud saya, secara teknis semua karakter dalam XML dalam SQL Server dikodekan sebagai UTF-16 Little Endian, jadi dalam pengertian itu mereka semua adalah Unicode. Tapi, apa yang Anda lihat hanyalah notasi yang lolos untuk karakter, dalam hal ini "2", yang memiliki nilai hex / biner "32".

Masalahnya hanyalah bahwa nama XML tidak dapat dimulai dengan angka. Tes berikut menunjukkan bahwa nama atribut atau nama elemen dimulai dengan angka mendapat kesalahan, tetapi dimulai dengan garis bawah ( _) atau huruf baik-baik saja.

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>
*/

Jadi, Anda perlu awalan nama kolom dengan karakter yang valid sebagai karakter awal untuk atribut XML atau nama elemen.


Juga, apakah Anda yakin itu "bekerja" dengan FOR XML AUTO? Dari apa yang saya lihat, itu hanya secara otomatis mengkonversi karakter "tidak valid" ke _x0032_:

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

Pengembalian:

<tmp _x0032_016="2" />
Solomon Rutzky
sumber