동적 SQL (피벗 쿼리)을 XML 출력으로 변환 할 때 날짜의 첫 번째 숫자가 유니 코드로 변환되는 이유는 무엇입니까?


11

피벗을 만들고 xml 데이터로 변환하기 위해 Bluefeet 의이 훌륭한 예제 /dba//a/25818/113298 을 사용하고 있습니다.

매개 변수 선언

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

다음으로 많은 코드가있는 CTE가 있으며 CTE의 최종 결과는 임시 DB에 배치됩니다 (예와 동일)

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 ;

여기에 이미지 설명을 입력하십시오

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 ;

결과

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

날짜를 놓친 이유가 왜 날짜의 일부만 유니 코드로 변환됩니까?

이 문제를 어떻게 해결할 수 있습니까?


어떤 SQL Server 버전입니까?
ypercubeᵀᴹ

Sql Server 2012, 그러나 요점은 아닙니다.이 경우에 중요한 xml 사양입니다.
Bunkerbuster

이것은 XY 문제처럼 보입니다. XML에서 날짜를 속성 이름으로 사용하면 의도 한대로 작동하더라도 권장되지 않습니다. 날짜를 속성 의 으로 저장 하거나 요소의 텍스트 로 저장하려는 경향이 있습니다 . 필요한 경우 속성 쌍을 사용하여 여러 요소를 만듭니다.
jpmc26

답변:


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 autoSQL Server를 사용하면 그렇게 합니다.


링크가 누락되었습니다 .xml 경로 (``)의 경우 root ( 'root')가 작동 중입니다.
벙커 버스터

6

첫 번째 문자는 유니 코드 자체가 아닙니다. 기술적으로 SQL Server 내의 XML의 모든 문자는 UTF-16 Little Endian으로 인코딩되므로 이러한 의미에서 모두 유니 코드입니다. 그러나 현재보고있는 것은 16 진수 / 이진수 값이 "32"인 문자 (이 경우 "2")에 대한 이스케이프 표기법입니다.

문제는 단순히 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.