(轉)SQL查詢案例:多行轉換為一行

禹過天晴發表於2017-03-13

原文: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 條警告訊息。

相關文章