Khi chuyển đổi SQL động (truy vấn trục) sang đầu ra xml, tại sao chữ số đầu tiên của ngày được chuyển thành unicode?


11

Tôi đang sử dụng ví dụ tuyệt vời này /dba//a/25818/113298 từ Bluefeet, để tạo một trục và chuyển đổi nó thành dữ liệu xml.

Khai báo thông số

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

Tiếp theo là một CTE với rất nhiều mã, endresult của CTE được đặt trong một DB tạm thời (giống như trong ví dụ)

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

Tạo cols (giống như ví dụ)

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

Tập kết quả là những gì tôi nên mong đợi

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

nhập mô tả hình ảnh ở đây

Khi tôi cố gắng chuyển đổi nó thành XML, các thuộc tính của tôi chỉ được chuyển đổi một phần

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 ;

kết quả

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

Tôi đã bỏ lỡ điều gì đó, tại sao chỉ là một phần của ngày được chuyển đổi thành unicode?

Làm thế nào tôi có thể sửa lỗi này?


Phiên bản SQL Server này dùng để làm gì?
ypercubeᵀᴹ

Sql Server 2012, nhưng đó không phải là vấn đề, đó là thông số kỹ thuật của xml quan trọng trong trường hợp này
Bunkerbuster

Đây có vẻ như là một vấn đề XY. Sử dụng một ngày làm tên thuộc tính trong XML có vẻ không được khuyến khích ngay cả khi điều này hoạt động như dự định. Tôi có xu hướng lưu trữ ngày tháng dưới dạng giá trị của một thuộc tính hoặc có thể là văn bản của một yếu tố, tùy thuộc vào những gì tôi dự định làm với nó. Nếu cần, tôi sẽ tạo nhiều phần tử với các cặp thuộc tính.
jpmc26

Câu trả lời:


14

Tên thuộc tính trong XML không được phép bắt đầu bằng một số, xem NameStartChar .

Bạn phải đưa ra các tên thay thế cho các thuộc tính của mình và mã hóa nó trong một @colsbiến riêng biệt chỉ định bí danh cột cho truy vấn trục động của bạn.

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

Kết quả;

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

Khi bạn đang sử dụng for xml autoSQL Server sẽ làm điều đó cho bạn.


Đó là liên kết bị thiếu, cũng cho đường dẫn xml (''), root ('root') hiện đang hoạt động.
Bunkerbuster

6

Ký tự đầu tiên không phải là Unicode, mỗi giây. Ý tôi là, về mặt kỹ thuật, tất cả các ký tự trong XML trong SQL Server đều được mã hóa dưới dạng UTF-16 Little Endian, vì vậy theo nghĩa đó, chúng đều là Unicode. Nhưng, những gì bạn đang thấy chỉ là ký hiệu thoát cho một ký tự, trong trường hợp này là "2", có giá trị hex / nhị phân là "32".

Vấn đề đơn giản là tên XML không thể bắt đầu bằng một số. Các thử nghiệm sau đây cho thấy tên thuộc tính hoặc tên thành phần bắt đầu bằng một số bị lỗi, nhưng bắt đầu bằng dấu gạch dưới ( _) hoặc một chữ cái là tốt.

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

Vì vậy, bạn cần phải thêm tiền tố vào các tên cột bằng một ký tự hợp lệ làm ký tự ban đầu cho một thuộc tính hoặc tên thành phần XML.


Ngoài ra, bạn có chắc chắn rằng nó đang "làm việc" với FOR XML AUTO? Từ những gì tôi có thể thấy, nó chỉ đơn giản là tự động chuyển đổi ký tự "không hợp lệ" thành _x0032_:

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

Trả về:

<tmp _x0032_016="2" />
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.