Bun*_*ter 11 xml sql-server pivot
我正在使用Bluefeet 的这个很好的例子https://dba.stackexchange.com/a/25818/113298,来创建一个数据透视表并将其转换为 xml 数据。
声明参数
DECLARE @cols AS NVARCHAR(MAX), @query AS NVARCHAR(MAX);
Run Code Online (Sandbox Code Playgroud)
接下来有一个代码很多的CTE,CTE的最终结果放在一个临时数据库中(与示例中相同)
SELECT
B.[StayDate] -- this is a date dd-mm-yyyy
, B.[Guid]
INTO #tempDates
FROM BaseSelection B
Run Code Online (Sandbox Code Playgroud)
生成 cols(与示例相同)
SELECT @cols = STUFF((SELECT distinct ',' +QUOTENAME(convert(char(10), [StayDate] , 120))
FROM #tempDates
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'');
Run Code Online (Sandbox Code Playgroud)
结果集是我应该期望的
set @query =
'SELECT [Guid],' + @cols +'
FROM
(
SELECT
[StayDate]
,[Guid]
FROM #tempDates
) A
pivot
(
count([StayDate])
for [StayDate] in (' + @cols +')
) p
'
EXEC sp_executesql @query ;
Run Code Online (Sandbox Code Playgroud)
当我尝试将其转换为 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 ;
Run Code Online (Sandbox Code Playgroud)
结果集
<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"
/>
Run Code Online (Sandbox Code Playgroud)
我错过了什么,为什么只有一部分日期转换为 unicode?
我怎样才能解决这个问题?
Mik*_*son 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,'');
Run Code Online (Sandbox Code Playgroud)
结果;
[2016-12-20] as [z2016-12-20],[2016-12-21] as [z2016-12-21]
Run Code Online (Sandbox Code Playgroud)
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,'');
Run Code Online (Sandbox Code Playgroud)
当您使用for xml auto
SQL Server 时,它会为您执行此操作。
第一个字符本身不是 Unicode。我的意思是,从技术上讲,SQL Server 中 XML 中的所有字符都编码为 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>
*/
Run Code Online (Sandbox Code Playgroud)
因此,您需要在列名前添加一个字符作为 XML 属性或元素名称的初始字符。
另外,您确定它正在“工作”FOR XML AUTO
吗?从我所见,它只是将“无效”字符自动转换为_x0032_
:
SELECT tmp.* FROM (SELECT 2) tmp([2016]) FOR XML AUTO;
Run Code Online (Sandbox Code Playgroud)
返回:
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>
*/
Run Code Online (Sandbox Code Playgroud)