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.