寫在前面
最近開發過程中,遇到一個需求是要將所查詢的多條結果匯總成一條結果展示,由於之前沒有接觸過這方面的業務,所以經過一番折騰之后,解決了需求,這里特此記錄一下,以供后續參考!
1、問題復現
這里以一個例子進行說明:
需求:一個員工每月是否完成了打卡,要求統計員工當月完成和未完成日期,展示結果如下:
測試的數據庫表字段如下:
CREATE TABLE `time_summary` ( `id` int NOT NULL AUTO_INCREMENT, `emp_id` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '員工號', `emp_name` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '員工姓名', `time_date` date DEFAULT NULL COMMENT '填報日期', `finish_flag` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '完成標志:0:未完成,1:已完成', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
測試數據如下:

INSERT INTO `time_summary`(`id`, `emp_id`, `emp_name`, `time_date`, `finish_flag`) VALUES (1, '100', '張三', '2020-06-24', '0'); INSERT INTO `time_summary`(`id`, `emp_id`, `emp_name`, `time_date`, `finish_flag`) VALUES (2, '100', '張三', '2020-06-23', '0'); INSERT INTO `time_summary`(`id`, `emp_id`, `emp_name`, `time_date`, `finish_flag`) VALUES (3, '100', '張三', '2020-06-22', '0'); INSERT INTO `time_summary`(`id`, `emp_id`, `emp_name`, `time_date`, `finish_flag`) VALUES (4, '100', '張三', '2020-06-19', '0'); INSERT INTO `time_summary`(`id`, `emp_id`, `emp_name`, `time_date`, `finish_flag`) VALUES (5, '100', '張三', '2020-06-18', '0'); INSERT INTO `time_summary`(`id`, `emp_id`, `emp_name`, `time_date`, `finish_flag`) VALUES (6, '100', '張三', '2020-06-17', '0'); INSERT INTO `time_summary`(`id`, `emp_id`, `emp_name`, `time_date`, `finish_flag`) VALUES (7, '100', '張三', '2020-06-16', '0'); INSERT INTO `time_summary`(`id`, `emp_id`, `emp_name`, `time_date`, `finish_flag`) VALUES (8, '100', '張三', '2020-06-15', '0'); INSERT INTO `time_summary`(`id`, `emp_id`, `emp_name`, `time_date`, `finish_flag`) VALUES (9, '100', '張三', '2020-06-12', '1'); INSERT INTO `time_summary`(`id`, `emp_id`, `emp_name`, `time_date`, `finish_flag`) VALUES (10, '100', '張三', '2020-06-11', '1'); INSERT INTO `time_summary`(`id`, `emp_id`, `emp_name`, `time_date`, `finish_flag`) VALUES (11, '100', '張三', '2020-06-10', '1'); INSERT INTO `time_summary`(`id`, `emp_id`, `emp_name`, `time_date`, `finish_flag`) VALUES (12, '100', '張三', '2020-06-09', '1'); INSERT INTO `time_summary`(`id`, `emp_id`, `emp_name`, `time_date`, `finish_flag`) VALUES (13, '100', '張三', '2020-06-08', '1'); INSERT INTO `time_summary`(`id`, `emp_id`, `emp_name`, `time_date`, `finish_flag`) VALUES (14, '100', '張三', '2020-06-05', '0'); INSERT INTO `time_summary`(`id`, `emp_id`, `emp_name`, `time_date`, `finish_flag`) VALUES (15, '100', '張三', '2020-06-04', '0'); INSERT INTO `time_summary`(`id`, `emp_id`, `emp_name`, `time_date`, `finish_flag`) VALUES (16, '100', '張三', '2020-06-03', '0'); INSERT INTO `time_summary`(`id`, `emp_id`, `emp_name`, `time_date`, `finish_flag`) VALUES (17, '100', '張三', '2020-06-02', '0'); INSERT INTO `time_summary`(`id`, `emp_id`, `emp_name`, `time_date`, `finish_flag`) VALUES (18, '100', '張三', '2020-06-01', '0'); INSERT INTO `time_summary`(`id`, `emp_id`, `emp_name`, `time_date`, `finish_flag`) VALUES (19, '101', '李四', '2020-06-24', '0'); INSERT INTO `time_summary`(`id`, `emp_id`, `emp_name`, `time_date`, `finish_flag`) VALUES (20, '101', '李四', '2020-06-23', '0'); INSERT INTO `time_summary`(`id`, `emp_id`, `emp_name`, `time_date`, `finish_flag`) VALUES (21, '101', '李四', '2020-06-22', '0'); INSERT INTO `time_summary`(`id`, `emp_id`, `emp_name`, `time_date`, `finish_flag`) VALUES (22, '101', '李四', '2020-06-19', '0'); INSERT INTO `time_summary`(`id`, `emp_id`, `emp_name`, `time_date`, `finish_flag`) VALUES (23, '101', '李四', '2020-06-18', '0'); INSERT INTO `time_summary`(`id`, `emp_id`, `emp_name`, `time_date`, `finish_flag`) VALUES (24, '101', '李四', '2020-06-17', '0'); INSERT INTO `time_summary`(`id`, `emp_id`, `emp_name`, `time_date`, `finish_flag`) VALUES (25, '101', '李四', '2020-06-16', '0'); INSERT INTO `time_summary`(`id`, `emp_id`, `emp_name`, `time_date`, `finish_flag`) VALUES (26, '101', '李四', '2020-06-15', '0'); INSERT INTO `time_summary`(`id`, `emp_id`, `emp_name`, `time_date`, `finish_flag`) VALUES (27, '101', '李四', '2020-06-12', '0'); INSERT INTO `time_summary`(`id`, `emp_id`, `emp_name`, `time_date`, `finish_flag`) VALUES (28, '101', '李四', '2020-06-11', '0'); INSERT INTO `time_summary`(`id`, `emp_id`, `emp_name`, `time_date`, `finish_flag`) VALUES (29, '101', '李四', '2020-06-10', '0'); INSERT INTO `time_summary`(`id`, `emp_id`, `emp_name`, `time_date`, `finish_flag`) VALUES (30, '101', '李四', '2020-06-09', '0'); INSERT INTO `time_summary`(`id`, `emp_id`, `emp_name`, `time_date`, `finish_flag`) VALUES (31, '101', '李四', '2020-06-08', '1'); INSERT INTO `time_summary`(`id`, `emp_id`, `emp_name`, `time_date`, `finish_flag`) VALUES (32, '101', '李四', '2020-06-05', '1'); INSERT INTO `time_summary`(`id`, `emp_id`, `emp_name`, `time_date`, `finish_flag`) VALUES (33, '101', '李四', '2020-06-04', '0'); INSERT INTO `time_summary`(`id`, `emp_id`, `emp_name`, `time_date`, `finish_flag`) VALUES (34, '101', '李四', '2020-06-03', '0'); INSERT INTO `time_summary`(`id`, `emp_id`, `emp_name`, `time_date`, `finish_flag`) VALUES (35, '101', '李四', '2020-06-02', '0'); INSERT INTO `time_summary`(`id`, `emp_id`, `emp_name`, `time_date`, `finish_flag`) VALUES (36, '101', '李四', '2020-06-01', '0'); INSERT INTO `time_summary`(`id`, `emp_id`, `emp_name`, `time_date`, `finish_flag`) VALUES (37, '102', '王五', '2020-06-24', '1'); INSERT INTO `time_summary`(`id`, `emp_id`, `emp_name`, `time_date`, `finish_flag`) VALUES (38, '102', '王五', '2020-06-23', '1'); INSERT INTO `time_summary`(`id`, `emp_id`, `emp_name`, `time_date`, `finish_flag`) VALUES (39, '102', '王五', '2020-06-22', '1'); INSERT INTO `time_summary`(`id`, `emp_id`, `emp_name`, `time_date`, `finish_flag`) VALUES (40, '102', '王五', '2020-06-19', '1'); INSERT INTO `time_summary`(`id`, `emp_id`, `emp_name`, `time_date`, `finish_flag`) VALUES (41, '102', '王五', '2020-06-18', '1'); INSERT INTO `time_summary`(`id`, `emp_id`, `emp_name`, `time_date`, `finish_flag`) VALUES (42, '102', '王五', '2020-06-17', '0'); INSERT INTO `time_summary`(`id`, `emp_id`, `emp_name`, `time_date`, `finish_flag`) VALUES (43, '102', '王五', '2020-06-16', '0'); INSERT INTO `time_summary`(`id`, `emp_id`, `emp_name`, `time_date`, `finish_flag`) VALUES (44, '102', '王五', '2020-06-15', '0'); INSERT INTO `time_summary`(`id`, `emp_id`, `emp_name`, `time_date`, `finish_flag`) VALUES (45, '102', '王五', '2020-06-12', '0'); INSERT INTO `time_summary`(`id`, `emp_id`, `emp_name`, `time_date`, `finish_flag`) VALUES (46, '102', '王五', '2020-06-11', '0'); INSERT INTO `time_summary`(`id`, `emp_id`, `emp_name`, `time_date`, `finish_flag`) VALUES (47, '102', '王五', '2020-06-10', '1'); INSERT INTO `time_summary`(`id`, `emp_id`, `emp_name`, `time_date`, `finish_flag`) VALUES (48, '102', '王五', '2020-06-09', '1'); INSERT INTO `time_summary`(`id`, `emp_id`, `emp_name`, `time_date`, `finish_flag`) VALUES (49, '102', '王五', '2020-06-08', '1'); INSERT INTO `time_summary`(`id`, `emp_id`, `emp_name`, `time_date`, `finish_flag`) VALUES (50, '102', '王五', '2020-06-05', '1'); INSERT INTO `time_summary`(`id`, `emp_id`, `emp_name`, `time_date`, `finish_flag`) VALUES (51, '102', '王五', '2020-06-04', '0'); INSERT INTO `time_summary`(`id`, `emp_id`, `emp_name`, `time_date`, `finish_flag`) VALUES (52, '102', '王五', '2020-06-03', '0'); INSERT INTO `time_summary`(`id`, `emp_id`, `emp_name`, `time_date`, `finish_flag`) VALUES (53, '102', '王五', '2020-06-02', '0'); INSERT INTO `time_summary`(`id`, `emp_id`, `emp_name`, `time_date`, `finish_flag`) VALUES (54, '102', '王五', '2020-06-01', '0');
這種情況下,我們一般可以將所有的情況查詢出來(這里以6月份數據為例),查詢SQL如下:
SELECT t.emp_id,t.emp_name,t.time_date,t.finish_flag from time_summary t where t.time_date >= '2020-06-01' and time_date <= '2020-06-30'
這樣查詢的結果如下:
這種顯然不滿足要求,針對這種情況,要怎么做呢?
2、問題解決
這時候需要使用 GROUP_CONCAT() 函數解決此問題。
說明:
1.GROUP_CONCAT() 中的值為你要合並的數據的字段名; SEPARATOR 函數是用來分隔這些要合並的數據的,默認以 逗號 分隔; ' '中是你要用哪個符號來分隔; 2.必須要用GROUP BY 語句來進行分組管理,不然所有的數據都會被合並成一條記錄
則此處對應的SQL語句如下,僅供參考!
SELECT su.emp_id, su.emp_name, a.notFinished, b.finished FROM ( SELECT t.emp_id, t.emp_name FROM time_summary t WHERE t.time_date >= '2020-06-01' AND t.time_date <= '2020-06-30' GROUP BY t.emp_id, t.emp_name ) su LEFT JOIN ( SELECT t.emp_id, t.emp_name, GROUP_CONCAT( SUBSTRING( t.time_date, 9, 2 ) SEPARATOR ',' ) AS notFinished FROM time_summary t WHERE t.time_date >= '2020-06-01' AND t.time_date <= '2020-06-30' AND t.finish_flag = '0' GROUP BY t.emp_id, t.emp_name ) a ON su.emp_id = a.emp_id LEFT JOIN ( SELECT t.emp_id, t.emp_name, GROUP_CONCAT( SUBSTRING( t.time_date, 9, 2 ) SEPARATOR ',' ) AS finished FROM time_summary t WHERE t.time_date >= '2020-06-01' AND t.time_date <= '2020-06-30' AND t.finish_flag = '1' GROUP BY t.emp_id, t.emp_name ) b ON su.emp_id = b.emp_id
3、內容擴展
在MySQL中字符串拼接常用的方法整理: 1、CONCAT() 2、CONCAT_WS() 3、GROUP_CONCAT()
3.1 CONCAT()
語法:CONCAT(str1,str2,...) 說明:作為最常用的字符串拼接方法,但是CONCAT函數在遇到拼接中的字符串出現 NULL 的情況,會返回 NULL
示例:
3.2 CONCAT_WS()
此種連接字符串的方法,從名字上就能看出:從concat with separator,使用分隔符連接字符串。
語法:CONCAT_WS(separator,str1,str2,…) 使用說明:第一個參數separator是用來分隔其它參數的分隔符。分隔符的位置放在要連接的兩個字符串之間。分隔符可以是一個字符串,也可以是其它參數 對比說明:concat_ws與concat相比優點: 1、可以使用分隔符連接字符串 2、若連接的字符串出現 NULL 值,concat_ws會忽略 NULL 值, 返回其他連接字符串
示例1:
示例2:
3.3 GROUP_CONCAT()
此種連接方法,主要是將某一字段的值連接成一行進行顯示,具體可以參看上面的問題實例。
語法 :group_concat( [DISTINCT] 連接的字段 [Order BY 排序字段 ASC/DESC] [Separator ‘分隔符’] ) 說明:可以連接多個字段,也可以對連接字段進行排序,默認以 逗號 分隔字段