原文:http://www.cnblogs.com/sammon/archive/2012/05/10/2494362.html
測試表與測試資料
CREATE TABLE TestTitle (
name VARCHAR(10),
titleVARCHAR(10)
);
INSERT INTO TestTitle VALUES ('張三', '程式設計師');
INSERT INTO TestTitle VALUES ('張三', '系統管理員');
INSERT INTO TestTitle VALUES ('張三', '網路管理員');
INSERT INTO TestTitle VALUES ('李四', '專案經理');
INSERT INTO TestTitle VALUES ('李四', '系統分析員');
要求
對於測試資料,要求查詢結果為:
張三程式設計師,系統管理員,網路管理員
李四專案經理,系統分析員
這種結構的結果。
思路
簡單檢視這個結果,很像對字元型的GROUP BY處理。
數值型別的可以SUM,但是字元型別的無法這麼處理。
只好依次MAX(1) + MAX(2) + MAX(3)這種辦法來處理。
實現
第一步,設定好分組的編號
SELECT
ROW_NUMBER() OVER(PARTITION BY name ORDER BY title) AS no,
name,
title
FROM
TestTitle
ORDER BY
name,
title
no name title
-------------------- ---------- ----------
1李四 系統分析員
2李四 專案經理
1張三 程式設計師
2張三 網路管理員
3張三 系統管理員
第二步,根據有編號的子查詢,進行分組處理
SELECT
name,
CASE WHEN COUNT(title) = 1 THEN MAX(title)
WHEN COUNT(title) = 2 THEN
MAX( CASE WHEN SubQuery.no = 1 THEN title + ',' ELSE '' END )
+ MAX( CASE WHEN SubQuery.no = 2 THEN titleELSE '' END )
WHEN COUNT(title) = 3 THEN
MAX( CASE WHEN SubQuery.no = 1 THEN title + ',' ELSE '' END )
+ MAX( CASE WHEN SubQuery.no = 2 THEN title + ','ELSE '' END )
+ MAX( CASE WHEN SubQuery.no = 3 THEN titleELSE '' END )
END AS new_title
FROM
(
SELECT
ROW_NUMBER() OVER(PARTITION BY name ORDER BY title) AS no,
name,
title
FROM
TestTitle
) subQuery
GROUP BY
name
執行結果
name new_title
---------- ----------------------------------
李四 系統分析員,專案經理
張三 程式設計師,網路管理員,系統管理員
對於SQL Server 2005 以上版本使用FOR XML的方式
測試表與測試資料要求
與前面的一樣
思路
首先把一個使用者的資料,單獨的讀取出來
然後按照分組進行處理
實現
第一步 把一個使用者的資料,單獨的讀取出來
SELECT
',' + title
FROM
TestTitle
WHERE
name = '張三'
FOR XML PATH('')
第二步Group By每個人
SELECT
name,
STUFF(
(
SELECT
',' + title
FROM
TestTitle subTitle
WHERE
name = TestTitle.name
FOR XML PATH('')
),
1, 1, '') AS allTitle
FROM
TestTitle
GROUP BY
name
執行結果
name allTitle
---------- --------------------------------
李四 專案經理,系統分析員
張三 程式設計師,系統管理員,網路管理員
對於SQL Server 2005 以上版本使用 CTE 的處理方式 (使用遞迴方式處理)
WITH t1 AS ( SELECT ROW_NUMBER() OVER(PARTITION BY name ORDER BY title) AS ID, name, title FROM TestTitle ), t2 AS ( SELECT t1.id,
t1.name, CAST(t1.title AS varchar(100)) AS title FROM
t1 WHERE t1.id = 1 UNION ALL SELECT t1.id, t2.name, CAST( t1.title + ',' + t2.title AS varchar(100)) AS title FROM t1, t2 WHERE t1.name = t2.name AND t1.id = (t2.id + 1) ) SELECT name, title FROM t2 WHERE NOT EXISTS ( SELECT 1 FROM t2 t22 WHERE t2.name = t22.name AND t2.id < t22.id );
name title
---------- ----------------------------------------------------------- ------------------------------- 張三 系統管理員,網路管理員,程式設計師
李四 專案經理,系統分析員
(2 行受影響)
對於MySQL使用 GROUP_CONCAT 函式 的方式進行處理(非常簡單)
mysql> SELECT -> name, -> GROUP_CONCAT(title) AS allTitle -> FROM -> TestTitle -> GROUP BY -> name; +------+------------------------------+ | name | allTitle | +------+------------------------------+ | 李四 | 專案經理,系統分析員 | | 張三 | 程式設計師,系統管理員,網路管理員 | +------+------------------------------+ 2 rows in set (0.00 sec)
對於Oracle使用 WMSYS.WM_CONCAT 函式 的方式進行處理(也非常簡單)
SQL> SQL> SELECT 2 name, 3 WMSYS.WM_CONCAT(title) AS allTitle 4 FROM 5 TestTitle 6 GROUP BY 7 name;
NAME ---------- ALLTITLE ------------------------------------------- 李四 專案經理,系統分析員
張三 程式設計師,系統管理員,網路管理員
對於 DB2 ,也是使用 CTE 遞迴的方式處理
WITH t1 (id, name, title) AS ( SELECT ROW_NUMBER() OVER(PARTITION BY name ORDER BY title) AS ID, name, title FROM TestTitle ), t2 (id, name, title) AS ( SELECT t1.id, t1.name, CAST(t1.title AS varchar(100)) AS title FROM t1 WHERE t1.id = 1 UNION ALL SELECT t1.id, t2.name, CAST( t1.title || ',' || t2.title AS varchar(100)) AS title FROM t1, t2 WHERE t1.name = t2.name AND t1.id = (t2.id + 1) ) SELECT name, title FROM t2 WHERE NOT EXISTS ( SELECT 1 FROM t2 t22 WHERE t2.name = t22.name AND t2.id < t22.id );
NAME TITLE
---------- --------------------------------------------------------------------- ------------------------------- SQL0347W 遞迴公共表表示式 "WZQ.T2" 可能包含無限迴圈。 SQLSTATE=01605
李四 專案經理,系統分析員
張三 網路管理員,系統管理員,程式設計師
已選擇 2 條記錄,列印 1 條警告訊息。