При преобразовании динамического SQL (сводный запрос) в вывод xml, почему первая цифра даты преобразуется в unicode?

Я использую этот отличный пример https://dba.stackexchange.com/a/25818/113298 от Bluefeet, чтобы создать стержень и преобразовать его в XML-данные.

Объявление параметра

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

Далее есть CTE с большим количеством кода, endresult CTE помещается в временную БД (то же, что и в примере)

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

Генерация столбцов (такая же, как в примере)

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 ;

 введите описание изображения здесь>> </a> </p>

<p> Когда я пытаюсь преобразовать его в XML, мои атрибуты только частично преобразуются </p>

<pre><code>---- +: = 4 = + ----</code></pre>

<p> ResultSet </p>

<pre><code>---- +: = 5 = + ----</code></pre>

<p> Я что-то пропустил, почему только часть даты конвертирована в Юникод? </p>

<p> Как я могу это исправить? </p></body></html>

10 голосов | спросил Bunkerbuster 20 TueEurope/Moscow2016-12-20T16:52:02+03:00Europe/Moscow12bEurope/MoscowTue, 20 Dec 2016 16:52:02 +0300 2016, 16:52:02

2 ответа


14

Имена атрибутов в XML не могут начинаться с числа, см. NameStartChar .

Вам нужно придумать альтернативные имена для ваших атрибутов и закодировать их в отдельной переменной @cols, определяющей псевдонимы столбцов для вашего динамического стержня запрос.

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 auto SQL Server делает это для вас.

ответил Mikael Eriksson 20 TueEurope/Moscow2016-12-20T17:48:15+03:00Europe/Moscow12bEurope/MoscowTue, 20 Dec 2016 17:48:15 +0300 2016, 17:48:15
5

Первый символ не является 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" />
ответил Solomon Rutzky 20 TueEurope/Moscow2016-12-20T17:48:43+03:00Europe/Moscow12bEurope/MoscowTue, 20 Dec 2016 17:48:43 +0300 2016, 17:48:43

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132