USE TEMPDB
GO
IF OBJECT_ID('TB') IS NOT NULL DROP TABLE TB
GO
CREATE TABLE TB(
ID INT
,VAL VARCHAR(50)
)
GO
INSERT INTO TB
SELECT 1,'A2' UNION ALL
SELECT 1,'A1' UNION ALL
SELECT 2,'B1' UNION ALL
SELECT 2,'B2' UNION ALL
SELECT 3,'C1'
GO
IF OBJECT_ID('FUN_MU') IS NOT NULL DROP FUNCTION FUN_MU
GO
--自定义函数方式
CREATE FUNCTION FUN_MU(@ID INT)
RETURNS VARCHAR(MAX)
AS
BEGIN
DECLARE @STR VARCHAR(MAX)
SELECT @STR=ISNULL(@STR+',','')+VAL
FROM TB
WHERE ID=@ID
ORDER BY VAL
RETURN @STR
END
GO
SELECT ID,DBO.FUN_MU(ID)
FROM TB
GROUP BY ID
/*
1 A1,A2
2 B1,B2
3 C1
*/
/*
这个方法我比较常用,效率不错,兼容2K,配置比较灵活,不过缺点就是每次都要新建一个函数 -_-||
拼接时的方式比较灵活,这里用ISNULL只是为了去掉第一个逗号,还有一些其它的写法不一一列出了。
*/
--XML方式
SELECT ID
,STUFF(
(SELECT ','+VAL FROM TB T2 WHERE T2.ID=T1.ID ORDER BY VAL FOR XML PATH(''))
,1,1,'')
FROM TB T1
GROUP BY ID
/*
1 A1,A2
2 B1,B2
3 C1
*/
/*
2005以后的版本才能用,这是最精简的版本。这个写法的优点是可以直接用查询完成拼接,缺点就是大数据量时非常非常非常慢。
我在小数据量做聚合时常用。
*/
--CTE方式
;WITH MU AS (
SELECT *,ROW_NUMBER() OVER (PARTITION BY ID ORDER BY VAL) AS NID FROM TB
),MU2 AS (
SELECT ID,NID,CONVERT(VARCHAR(MAX),VAL) AS NVAL
FROM MU
WHERE NID=1
UNION ALL
SELECT
MU.ID,MU.NID,MU2.NVAL+','+MU.VAL
FROM MU
INNER JOIN MU2 ON MU.ID=MU2.ID AND MU.NID=MU2.NID+1
)
SELECT ID,NVAL
FROM MU2 T1
WHERE NOT EXISTS(
SELECT 1 FROM MU2 T2 WHERE T2.ID=T1.ID AND T2.NID>T1.NID
)
ORDER BY ID
/*
1 A1,A2
2 B1,B2
3 C1
*/
/*
CTE也是2005以后才有的功能,拼接字符串只是一个功能,它的递归运算才是最好用的功能。
这种写法其实不太常用,因为它无法写到一个复杂查询中,只是经常作为一个CTE功能展示的例子
*/