MySQL GROUP BY分組取欄位最大值
假設有一個業務場景,需要查詢使用者登入記錄資訊,其中表結構如下:
-
CREATE TABLE `tb` (
-
`id` int(11) NOT NULL AUTO_INCREMENT,
-
`uid` int(11) NOT NULL,
-
`ip` varchar(16) NOT NULL,
-
`login_time` datetime,
-
PRIMARY KEY (`id`),
-
KEY (`uid`)
- );
再來點測試資料:
-
INSERT INTO tb SELECT null, 1001, '192.168.1.1', '2016-01-01 16:30:47';
-
INSERT INTO tb SELECT null, 1003, '192.168.1.153', '2016-01-01 19:30:51';
-
INSERT INTO tb SELECT null, 1001, '192.168.1.61', '2016-01-01 16:50:41';
-
INSERT INTO tb SELECT null, 1002, '192.168.1.31', '2016-01-01 18:30:21';
-
INSERT INTO tb SELECT null, 1002, '192.168.1.66', '2016-01-01 19:12:32';
-
INSERT INTO tb SELECT null, 1001, '192.168.1.81', '2016-01-01 19:53:09';
- INSERT INTO tb SELECT null, 1001, '192.168.1.231', '2016-01-01 19:55:34';
表資料情況:
-
+----+------+---------------+---------------------+
-
| id | uid | ip | login_time |
-
+----+------+---------------+---------------------+
-
| 1 | 1001 | 192.168.1.1 | 2016-01-01 16:30:47 |
-
| 2 | 1003 | 192.168.1.153 | 2016-01-01 19:30:51 |
-
| 3 | 1001 | 192.168.1.61 | 2016-01-01 16:50:41 |
-
| 4 | 1002 | 192.168.1.31 | 2016-01-01 18:30:21 |
-
| 5 | 1002 | 192.168.1.66 | 2016-01-01 19:12:32 |
-
| 6 | 1001 | 192.168.1.81 | 2016-01-01 19:53:09 |
-
| 7 | 1001 | 192.168.1.231 | 2016-01-01 19:55:34 |
- +----+------+---------------+---------------------+
如果只需要針對使用者查出其最後登入的時間,可以簡單寫出:
-
SELECT uid, max(login_time)
-
FROM tb
-
GROUP BY uid;
-
-
+------+---------------------+
-
| uid | max(login_time) |
-
+------+---------------------+
-
| 1001 | 2016-01-01 19:55:34 |
-
| 1002 | 2016-01-01 19:12:32 |
-
| 1003 | 2016-01-01 19:30:51 |
- +------+---------------------+
若還需要查詢使用者最後登入時的其他資訊,就不能用這種sql寫了:
- -- 錯誤寫法
-
SELECT uid, ip, max(login_time)
-
FROM tb
-
GROUP BY uid;
- -- 錯誤寫法
(如果sql_mode開啟了only_full_group_by,則不會執行成功。)
可能ip欄位會取uid分組前的第一個row的值,顯然不是所需資訊
寫法①
那麼寫一個子查詢吧:
-
SELECT a.uid, a.ip, a.login_time
-
FROM tb a
-
WHERE a.login_time in (
-
SELECT max(login_time)
-
FROM tb
- GROUP BY uid);
寫法②
再或者換一個寫法:
-
SELECT a.uid, a.ip, a.login_time
-
FROM tb a
-
WHERE a.login_time = (
-
SELECT max(login_time)
-
FROM tb
- WHERE a.uid = uid);
順便測了一下
在5.6以前的版本中,寫法②這條sql在大資料量的情況下,執行計劃不理想,目測效能不佳。
在5.6及以後的版本中,寫法②這條sql會快很多,執行計劃也有了改變
5.5.50:
-
+----+--------------------+-------+------+---------------+------+---------+------+------+-------------+
-
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
-
+----+--------------------+-------+------+---------------+------+---------+------+------+-------------+
-
| 1 | PRIMARY | a | ALL | NULL | NULL | NULL | NULL | 7 | Using where |
-
| 2 | DEPENDENT SUBQUERY | tb | ALL | uid | NULL | NULL | NULL | 7 | Using where |
- +----+--------------------+-------+------+---------------+------+---------+------+------+-------------+
5.6.30:
-
+----+--------------------+-------+------+---------------+------+---------+------------+------+-------------+
-
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
-
+----+--------------------+-------+------+---------------+------+---------+------------+------+-------------+
-
| 1 | PRIMARY | a | ALL | NULL | NULL | NULL | NULL | 7 | Using where |
-
| 2 | DEPENDENT SUBQUERY | tb | ref | uid | uid | 4 | test.a.uid | 1 | NULL |
- +----+--------------------+-------+------+---------------+------+---------+------------+------+-------------+
寫法③
索性直接改成join效能會更加好:
-
SELECT a.uid, a.ip, a.login_time
-
FROM (SELECT uid, max(login_time) login_time
-
FROM tb
-
GROUP BY uid
- ) b JOIN tb a ON a.uid = b.uid AND a.login_time = b.login_time;
當然,結果都相同:
-
+------+---------------+---------------------+
-
| uid | ip | login_time |
-
+------+---------------+---------------------+
-
| 1003 | 192.168.1.153 | 2016-01-01 19:30:51 |
-
| 1002 | 192.168.1.66 | 2016-01-01 19:12:32 |
-
| 1001 | 192.168.1.231 | 2016-01-01 19:55:34 |
- +------+---------------+---------------------+
當然……如果要分組取最小值直接改對應函式和符號就行了。
作者微信公眾號(持續更新)
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/29773961/viewspace-2125230/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- MySQL - 分組連線欄位函式GROUP_CONCAT的使用MySql函式
- mongodb 取欄位最大值MongoDB
- mysql group_concat 實現把分組欄位寫成一行的方法MySql
- MySQL 欄位擷取拼接MySql
- SQL-分組聚合 - 單欄位分組SQL
- SqlServer根據特定欄位分組後,對需要欄位進行分組拼接SQLServer
- pandas 分組合並欄位(qbit)
- list集合根據某欄位分組
- group by分組查詢
- MYSQL學習筆記8: DQL分組查詢(group by)MySql筆記
- MySql先分組統計總記錄數,再獲取記錄數中的最大值MySql
- Mysql系列第九講 分組查詢詳解(group by & having)MySql
- MySQL 分組後取最新記錄MySql
- python獲取、修改mysql資料庫欄位屬性PythonMySql資料庫
- vxe-table 實現表格資料分組,按指定欄位資料分組
- MySQL 欄位約束MySql
- mysql group by 取想要的結果MySql
- mysql資料表按照某個欄位分類輸出MySql
- MySQL-刪除欄位MySql
- MySQL 大欄位問題MySql
- MySQL8.0——Resource Group(資源組)MySql
- [SQL]group by和order by是否能寫欄位別名SQL
- python-進階教程-根據欄位將記錄分組Python
- js物件陣列(JSON) 根據某個共同欄位 分組物件陣列JSON
- SQL 如何查詢每個分組都出現的欄位值SQL
- mysql表操作(alter)/mysql欄位型別MySql型別
- MySQL欄位新增註釋,但不改變欄位的型別MySql型別
- MYSQL——分組MySql
- MySQL-建立計算欄位MySql
- MySQL欄位的取值範圍MySql
- MySQL欄位型別最全解析MySql型別
- Android開發 - 掌握ConstraintLayout(九)分組(Group)AndroidAI
- mybatis&plus系列------Mysql的JSON欄位的讀取和轉換MyBatisMySqlJSON
- select,value,pluck 欄位區分
- mysql 分組取每個組的前幾名的問題MySql
- arcgis欄位值計算(擷取A欄位前8位+按照順序計算8位)
- java8的stream將一個List轉為按照某個欄位分組的map,再按照另一個欄位取max最終得到一個mapJava
- mysql使用group by實現組內排序實戰MySql排序
- golang將切片或陣列根據某個欄位進行分組Golang陣列