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 By分組MySql
- mysql group_concat 實現把分組欄位寫成一行的方法MySql
- SqlServer根據特定欄位分組後,對需要欄位進行分組拼接SQLServer
- Oracle和MySQL分組查詢GROUP BYOracleMySql
- MySQL 欄位擷取拼接MySql
- pandas 分組合並欄位(qbit)
- [Mysql 查詢語句]——分組查詢group byMySql
- list集合根據某欄位分組
- group by分組查詢
- SQL 分組排序group bySQL排序
- MySQL-取某個欄位表中每組幾行資料方式MySql
- MYSQL學習筆記8: DQL分組查詢(group by)MySql筆記
- Sql group by 分組取時間最新的一條資料SQL
- MySql先分組統計總記錄數,再獲取記錄數中的最大值MySql
- 更改MySql表和欄位區分大小寫MySql
- MySQL 分組後取最新記錄MySql
- 從10g開始CBO下group by之後不能保證資料是按照分組欄位排序的!排序
- Mysql系列第九講 分組查詢詳解(group by & having)MySql
- [備查]使用 SPQuery 查詢 "Person or Group" 欄位
- SQL優化:組內排序取最大值SQL優化排序
- [MySQL] 分組排序取前N條記錄以及生成自動數字序列,類似group by後 limitMySql排序MIT
- MySQL 欄位約束MySql
- mysql中文欄位排序MySql排序
- mysql group by 取想要的結果MySql
- MySQL8.0——Resource Group(資源組)MySql
- SQL 如何查詢每個分組都出現的欄位值SQL
- oracle分組查詢獲得組的最大值記錄Oracle
- MYSQL——分組MySql
- SQL最佳化:組內排序取最大值SQL排序
- oracle 高階分組group by cube擴充Oracle
- oracle group by與分組列為null空OracleNull
- python獲取、修改mysql資料庫欄位屬性PythonMySql資料庫
- mysql資料表按照某個欄位分類輸出MySql
- mysql 分組取每個組的前幾名的問題MySql
- js物件陣列(JSON) 根據某個共同欄位 分組物件陣列JSON
- python-進階教程-根據欄位將記錄分組Python