Dinamik SQL (pivot sorgusu) xml çıktısına dönüştürülürken, tarihin ilk basamağı neden unicode'a dönüştürülür?


11

Bir pivot oluşturmak ve xml verilerine dönüştürmek için Bluefeet'ten bu harika örneği https://dba.stackexchange.com/a/25818/113298 kullanıyorum .

Paramın ilan edilmesi

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

Daha sonra çok sayıda koda sahip bir CTE var, CTE'nin son sonucu geçici bir DB'ye yerleştiriliyor (örnekte olduğu gibi)

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

Kolonların oluşturulması (örnekle aynı)

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

Sonuç kümesi beklediğim şey

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

resim açıklamasını buraya girin

XML'e dönüştürmeye çalıştığımda özniteliklerim sadece kısmen dönüştürülüyor

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 ;

sonuç kümesi

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

Bir şeyi kaçırdım mı, neden tarihin sadece bir kısmı unicode'a dönüştürülüyor?

Bunu nasıl düzeltebilirim?


SQL Server'ın hangi sürümü bu?
— ypercubeᵀᴹ

Sql Server 2012, ama mesele bu değil, bu durumda önemli olan xml özellikleri
— Bunkerbuster

Bu bir XY sorunu gibi görünüyor. XML'de bir tarihin öznitelik adı olarak kullanılması, amaçlandığı şekilde çalışsa bile kötü bir şekilde tavsiye edilir. Tarihi , bir özniteliğin değeri olarak ya da belki onunla yapmayı planladığım şeye bağlı olarak bir öğenin metni olarak saklama eğilimindeyim . Gerekirse, özellik çiftleri ile birden fazla öğe yaparım.
— jpmc26

Yanıtlar:


14

XML'deki öznitelik adlarının bir sayıyla başlamasına izin verilmez, bkz. NameStartChar .

Öznitelikleriniz için alternatif adlar bulmanız ve bunu @cols, dinamik pivot sorgunuz için sütun takma adlarını belirten ayrı bir değişkente kodlamanız gerekir.

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

Sonuç;

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

for xml autoSQL Server kullanırken bunu sizin için yapar.


Bu eksik bağlantıydı, ayrıca xml yolu ('') için root ('root') şimdi çalışıyor.
— Bunkerbuster

6

İlk karakter Unicode değil, kendi başına. Yani, teknik olarak SQL Server içindeki XML'deki tüm karakterler UTF-16 Little Endian olarak kodlanmıştır, bu yüzden hepsi Unicode'dur. Ancak, gördüğünüz şey sadece bir karakter için kaçan gösterimdir, bu durumda "2", onaltılık / ikili değeri "32" dir.

Sorun, XML adlarının bir sayı ile başlayamamasıdır. Aşağıdaki sınamalar, bir sayıyla başlayan öznitelik adının veya öğe adının hata aldığını, ancak alt çizgi ( _) veya harfle başlamanın gayet iyi olduğunu gösterir.

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

Bu nedenle, sütun adlarını, bir XML özelliği veya öğe adı için başlangıç ​​karakteri olarak geçerli bir karakterle ön ek yapmanız gerekir.


Ayrıca, bununla "çalıştığından" emin misiniz FOR XML AUTO? Ne görebiliyorum, sadece otomatik olarak "geçersiz" karakteri dönüştürmek için _x0032_:

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

İadeler:

<tmp _x0032_016="2" />
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.