เมื่อแปลงไดนามิก SQL (เคียวรี pivot) ไปยังเอาต์พุต xml ทำไมตัวเลขแรกของวันที่ถูกแปลงเป็นยูนิโคด


11

ฉันใช้ตัวอย่างที่ยอดเยี่ยมนี้/dba//a/25818/113298จาก Bluefeet เพื่อสร้างเดือยและเปลี่ยนเป็นข้อมูล xml

ประกาศพารามิเตอร์

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

ถัดไปคือ CTE ที่มีรหัสจำนวนมาก endresult ของ CTE จะถูกใส่ใน temp DB (เช่นเดียวกับในตัวอย่าง)

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

การสร้าง cols (เช่นเดียวกับตัวอย่าง)

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

ชุดผลลัพธ์คือสิ่งที่ฉันควรคาดหวัง

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

ป้อนคำอธิบายรูปภาพที่นี่

เมื่อฉันพยายามแปลงให้เป็น XML คุณสมบัติของฉันจะถูกแปลงเพียงบางส่วนเท่านั้น

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

ฉันพลาดบางสิ่งบางอย่างทำไมเพียงบางส่วนของวันที่แปลงเป็น unicode?

ฉันจะแก้ไขสิ่งนี้ได้อย่างไร


SQL Server รุ่นนี้ใช้ทำอะไร?
ypercubeᵀᴹ

Sql Server 2012, แต่นั่นไม่ใช่ประเด็น, มันเป็นสเปคของ xml ที่สำคัญในกรณีนี้
Bunkerbuster

ดูเหมือนว่าจะเป็นปัญหา XY การใช้วันที่เป็นชื่อแอตทริบิวต์ใน XML ดูเหมือนจะไม่แนะนำให้ใช้ ฉันมีแนวโน้มที่จะเก็บวันที่เป็นค่าของแอตทริบิวต์หรืออาจเป็นข้อความขององค์ประกอบขึ้นอยู่กับสิ่งที่ฉันวางแผนจะทำ หากจำเป็นฉันจะสร้างองค์ประกอบหลายรายการพร้อมคู่ของแอตทริบิวต์
jpmc26

คำตอบ:


14

ชื่อแอตทริบิวต์ในรูปแบบ XML ไม่ได้รับอนุญาตจะเริ่มต้นด้วยตัวเลขดูNameStartChar

คุณต้องสร้างชื่ออื่นสำหรับแอตทริบิวต์ของคุณและเข้ารหัสใน@colsตัวแปรแยกต่างหากที่ระบุชื่อแทนคอลัมน์สำหรับเคียวรี pivot แบบไดนามิกของคุณ

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

ผลลัพธ์;

[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 จะทำเพื่อคุณ


นั่นคือลิงค์ที่ขาดหายไปเช่นกันกับพา ธ xml (''), รูท ('รูท') ก็ใช้งานได้
บังเกอร์บัสเตอร์

6

อักขระตัวแรกไม่ใช่ Unicode ฉันหมายความว่าในทางเทคนิคแล้วตัวละครทั้งหมดใน XML ภายใน SQL Server นั้นถูกเข้ารหัสเป็น UTF-16 Little Endian ดังนั้นในแง่นั้นพวกเขาทั้งหมดเป็น Unicode แต่สิ่งที่คุณเห็นเป็นเพียงเครื่องหมายหนีสำหรับอักขระในกรณีนี้ "2" ซึ่งมีค่าฐานสิบหก / เลขฐานสองของ "32"

ปัญหาก็คือว่าชื่อ XML ไม่สามารถเริ่มต้นด้วยตัวเลข การทดสอบต่อไปนี้แสดงว่าชื่อแอ็ตทริบิวต์หรือชื่อองค์ประกอบที่ขึ้นต้นด้วยตัวเลขได้รับข้อผิดพลาด แต่เริ่มต้นด้วยเครื่องหมายขีดล่าง ( _) หรือตัวอักษรนั้นใช้ได้

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

ดังนั้นคุณต้องนำหน้าชื่อคอลัมน์ด้วยอักขระที่ถูกต้องเป็นอักขระเริ่มต้นสำหรับแอตทริบิวต์ XML หรือชื่อองค์ประกอบ


นอกจากนี้คุณแน่ใจหรือว่ามันเป็น "ทำงาน" ด้วยFOR XML AUTO? จากสิ่งที่ฉันเห็นมันเป็นเพียงการแปลงอักขระ "ไม่ถูกต้อง" เป็น_x0032_:

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

ผลตอบแทน:

<tmp _x0032_016="2" />
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.