동적 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.