SQL Server中有提供一个FOR XML PATH的子句(不知道能不能叫函数),用来将查询结果行输出成XML格式,我们可以通过这个语法做一些变通实现一些特定的功能,比如说行转列。要会变通的话,当然首先是要知道FOR XML PATH的语法。
FOR XML PATH的简单语法
假设有一个hobby表(爱好),表中有两个字段,一个是hobbyID(爱好id),一个是hName(爱好名称)。
这样,我们执行一条最简单的带FOR XML PATH子句的SQL语句,看看查询出来的结果。
SELECT * FROM hobby FOR XML PATH;
<row> <hobbyID>1</hobbyID> <hName>爬山</hName> </row> <row> <hobbyID>2</hobbyID> <hName>游泳</hName> </row> <row> <hobbyID>3</hobbyID> <hName>美食</hName> </row>
由结果可见FOR XML PATH子句可以将查询结果行输出成XML格式。
FOR XML PATH的变通
更多的,FOR XML PATH子句是支持传递参数的,即FOR XML PATH(schema),这样的话在查询的时候就会将行标签<row>替换为<schema>,要注意的是schema必须是字符串。
SELECT * FROM hobby FOR XML PATH('yanggb');
<yanggb> <hobbyID>1</hobbyID> <hName>爬山</hName> </yanggb> <yanggb> <hobbyID>2</hobbyID> <hName>游泳</hName> </yanggb> <yanggb> <hobbyID>3</hobbyID> <hName>美食</hName> </yanggb>
这时候,就可以利用XML的特点,即空标签不会存在的特定,将行标签<row>去掉。
SELECT * FROM hobby FOR XML PATH('');
<hobbyID>1</hobbyID> <hName>爬山</hName> <hobbyID>2</hobbyID> <hName>游泳</hName> <hobbyID>3</hobbyID> <hName>美食</hName>
那能更改/去除行标签<row>,能不能更改/去除列标签呢?答案是可以的,可以通过给列起别名的方式来更改/除列标签。要注意的是这里的别名也必须是字符串。
SELECT hobbID AS AA, hName AS BB FROM hobby FOR XML PATH('');
<AA>1</AA> <BB>爬山</BB> <AA>2</AA> <BB>游泳</BB> <AA>3</AA> <BB>美食</BB>
与去除行标签<row>的方式不一样的是,去除列标签不能将别名定义为空字符串,否则数据库引擎会报错误:[Err] 42000 - [SQL Server]缺少对象或列名,或者对象或列名为空。对于 SELECT INTO 语句,请确保每列均具有名称。对于其他语句,请查找空的别名。不允许使用定义为 "" 或 [] 的别名。请将别名更改为有效名称。
那么要怎么去除列标签呢,做法是给字段加上空字符串(加任何字符串都可以,我的理解是这种做法修改了列值,在没有起别名的情况下,原来的列标签不再匹配列值,数据库引擎会将自动该列标签去除)。
SELECT hobbID + '', hName + '' FROM hobby FOR XML PATH('');
1爬山2游泳3美食
FOR XML PATH实现行转列
根据上面的FOR XML PATH的变通的内容,我们就可以来实现行转列了。
SELECT hName, (SELECT ',' + hName FROM hobby FOR XML PATH('')) AS hNames FROM hobby FOR XML PATH('');
这样我们就能得到一个所有爱好拼接起来的列hNames。
这时候我们会发现hNames字段值多了一个逗号,使用STUFF函数(推荐)或REPLACE函数去除即可。
更多的,可以在FOR XML PATH子句前添加WHERE子句限定条件范围来限定行转列的范围(也可以使用自连接限定当前行转列的范围)。
当然了,SQL SERVER还提供了另外的行转列的PRIVOT函数和列转行的UNPRIVOT函数。
"一个姑娘不会因为你专一痴情就喜欢你,只会因为你优秀而喜欢你。"