MySQL取每組的前N條記錄
阿新 • • 發佈:2019-01-14
MySQL 分組後取每組前N條資料
與oracle的 rownumber() over(partition by xxx order by xxx )語句類似,即:對錶分組後排序
CREATE TABLE `mygoods` ( `goods_id` int(11) unsigned NOT NULL AUTO_INCREMENT, `cat_id` int(11) NOT NULL DEFAULT '0', `price` tinyint(3) NOT NULL DEFAULT '0', `status`tinyint(3) DEFAULT '1', PRIMARY KEY (`goods_id`), KEY `icatid` (`cat_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; INSERT INTO `mygoods` VALUES (1, 101, 90, 0); INSERT INTO `mygoods` VALUES (2, 101, 99, 1); INSERT INTO `mygoods` VALUES (3, 102, 98, 0); INSERT INTO `mygoods` VALUES(4, 103, 96, 0); INSERT INTO `mygoods` VALUES (5, 102, 95, 0); INSERT INTO `mygoods` VALUES (6, 102, 94, 1); INSERT INTO `mygoods` VALUES (7, 102, 93, 1); INSERT INTO `mygoods` VALUES (8, 103, 99, 1); INSERT INTO `mygoods` VALUES (9, 103, 98, 1); INSERT INTO `mygoods` VALUES (10, 103, 97, 1); INSERT INTO `mygoods` VALUES (11, 104, 96, 1); INSERT INTO `mygoods` VALUES (12, 104, 95, 1); INSERT INTO `mygoods` VALUES (13, 104, 94, 1); INSERT INTO `mygoods` VALUES (15, 101, 92, 1); INSERT INTO `mygoods` VALUES (16, 101, 93, 1); INSERT INTO `mygoods` VALUES (17, 101, 94, 0); INSERT INTO `mygoods` VALUES (18, 102, 99, 1); INSERT INTO `mygoods` VALUES (19, 105, 85, 1); INSERT INTO `mygoods` VALUES (20, 105, 89, 0); INSERT INTO `mygoods` VALUES (21, 105, 99, 1);
說明:
表mygoods為商品表,cat_id為分類id,goods_id為商品id,status為商品當前的狀態位(1:有效,0:無效)。
需求:每個分類下,找出兩個價格最高的有效的商品。
1.每個分類找出價格最高的兩個商品
mysql> select a.* -> from mygoods a -> where (select count(*) -> from mygoods -> where cat_id = a.cat_id and price > a.price ) <2 -> order by a.cat_id,a.price desc;
SQL解析:
cat_id = a.cat_id --是為了確定分組欄位
price > a.price --確定排序條件,由於是大於,則最大出現0次,第二大的出現1次,所以count(*)<2
+----------+--------+-------+--------+ | goods_id | cat_id | price | status | +----------+--------+-------+--------+ | 2 | 101 | 99 | 1 | | 17 | 101 | 94 | 0 | | 18 | 102 | 99 | 1 | | 3 | 102 | 98 | 0 | | 8 | 103 | 99 | 1 | | 9 | 103 | 98 | 1 | | 11 | 104 | 96 | 1 | | 12 | 104 | 95 | 1 | | 21 | 105 | 99 | 1 | | 20 | 105 | 89 | 0 | +----------+--------+-------+--------+ 10 rows in set (0.00 sec)
2.每個分類找出價格最高的有效的兩個商品(正確)
mysql> select a.* -> from mygoods a -> where (select count(*) from mygoods -> where cat_id = a.cat_id and price > a.price and status=1 ) <2 -> and status=1 -> order by a.cat_id,a.price desc ;
+----------+--------+-------+--------+ | goods_id | cat_id | price | status | +----------+--------+-------+--------+ | 2 | 101 | 99 | 1 | | 16 | 101 | 93 | 1 | | 18 | 102 | 99 | 1 | | 6 | 102 | 94 | 1 | | 8 | 103 | 99 | 1 | | 9 | 103 | 98 | 1 | | 11 | 104 | 96 | 1 | | 12 | 104 | 95 | 1 | | 21 | 105 | 99 | 1 | | 19 | 105 | 85 | 1 | +----------+--------+-------+--------+ 10 rows in set (0.00 sec)3.每個分類找出價格最高的有效的兩個商品(正確)
mysql> select a.* -> from mygoods a -> left join mygoods b -> on a.cat_id = b.cat_id and a.price < b.price and b.status=1 -> where a.status=1 -> group by a.goods_id,a.cat_id,a.price -> having count(b.goods_id) < 2 -> order by a.cat_id,a.price desc;
+----------+--------+-------+--------+ | goods_id | cat_id | price | status | +----------+--------+-------+--------+ | 2 | 101 | 99 | 1 | | 16 | 101 | 93 | 1 | | 18 | 102 | 99 | 1 | | 6 | 102 | 94 | 1 | | 8 | 103 | 99 | 1 | | 9 | 103 | 98 | 1 | | 11 | 104 | 96 | 1 | | 12 | 104 | 95 | 1 | | 21 | 105 | 99 | 1 | | 19 | 105 | 85 | 1 | +----------+--------+-------+--------+ 10 rows in set (0.00 sec)4.每個分類找出價格最高的有效的兩個商品(錯誤)
mysql> select a.* -> from mygoods a -> where (select count(*) from mygoods -> where cat_id = a.cat_id and price > a.price ) <2 and status=1 -> order by a.cat_id,a.price desc;
+----------+--------+-------+--------+ | goods_id | cat_id | price | status | +----------+--------+-------+--------+ | 2 | 101 | 99 | 1 | | 18 | 102 | 99 | 1 | | 8 | 103 | 99 | 1 | | 9 | 103 | 98 | 1 | | 11 | 104 | 96 | 1 | | 12 | 104 | 95 | 1 | | 21 | 105 | 99 | 1 | +----------+--------+-------+--------+ 7 rows in set (0.00 sec)由上可知,如果需要增加條件的話,需要在兩處增加條件。
可以將每個分組下的goods_id合併。
mysql> select cat_id,GROUP_CONCAT(goods_id) from mygoods group by cat_id;
+--------+------------------------+ | cat_id | GROUP_CONCAT(goods_id) | +--------+------------------------+ | 101 | 1,2,15,16,17 | | 102 | 3,5,6,7,18 | | 103 | 4,8,9,10 | | 104 | 11,12,13 | | 105 | 19,20,21 | +--------+------------------------+ 5 rows in set (0.00 sec)
https://blog.csdn.net/come_on_air/article/details/72902592
MySQL取每組的前N條記錄:使用自連線的方式
一、對分組的記錄取前N條記錄:例子:取前 2條最大(小)的記錄
1.用子查詢: SELECT * FROM right2 a WHERE 2 > ( SELECT COUNT(*) FROM right2 b WHERE b.id = a.id AND b.account > a.account ) ORDER BY a.id, a.account DESC 2.用exists半連線: SELECT * FROM right2 a WHERE EXISTS ( SELECT COUNT(*) FROM right2 b WHERE b.id = a.id AND a.account < b.account HAVING COUNT(*) < 2 ) ORDER BY a.id, a.account DESC 同理可以取組內最小的N條記錄: SELECT * FROM right2 a WHERE 2 > ( SELECT COUNT(*) FROM right2 b WHERE b.id = a.id AND b.account < a.account ) ORDER BY a.id, a.account DESC 用exists: SELECT * FROM right2 a WHERE EXISTS ( SELECT COUNT(*) FROM right2 b WHERE b.id = a.id AND a.account > b.account HAVING COUNT(*) < 2 ) ORDER BY a.id, a.account DESC SQLServer支援top - N: SELECT a.* FROM tb a WHERE val = ( SELECT top 3 val FROM tb WHERE NAME = a. NAME ) ORDER BY a. NAME
如果取每組的最大(小)一條記錄我常用:
SELECT id, val FROM t b INNER JOIN ( SELECT * FROM t a WHERE ORDER BY val DESC ) a ON a.id = b.id GROUP BY a.id ORDER BY id;
二.例項:取每組最大的前 N條
CREATE TABLE t2 ( id INT PRIMARY KEY, gid CHAR, col1 INT, col2 INT ) ENGINE = INNODB; INSERT INTO t2 VALUES (1, 'A', 31, 6), (2, 'B', 25, 83), (3, 'C', 76, 21), (4, 'D', 63, 56), (5, 'E', 3, 17), (6, 'A', 29, 97), (7, 'B', 88, 63), (8, 'C', 16, 22), (9, 'D', 25, 43), (10, 'E', 45, 28), (11, 'A', 2, 78), (12, 'B', 30, 79), (13, 'C', 96, 73), (14, 'D', 37, 40), (15, 'E', 14, 86), (16, 'A', 32, 67), (17, 'B', 84, 38), (18, 'C', 27, 9), (19, 'D', 31, 21), (20, 'E', 80, 63), (21, 'A', 89, 9), (22, 'B', 15, 22), (23, 'C', 46, 84), (24, 'D', 54, 79), (25, 'E', 85, 64), (26, 'A', 87, 13), (27, 'B', 40, 45), (28, 'C', 34, 90), (29, 'D', 63, 8), (30, 'E', 66, 40), (31, 'A', 83, 49), (32, 'B', 4, 90), (33, 'C', 81, 7), (34, 'D', 11, 12), (35, 'E', 85, 10), (36, 'A', 39, 75), (37, 'B', 22, 39), (38, 'C', 76, 67), (39, 'D', 20, 11), (40, 'E', 81, 36);
取每組gid 最大的前N條記錄:使用自連線或則半連線:
*N=1時:
自連線:降序排好後group by取每組最大的一條。
SELECT * FROM ( SELECT * FROM t2 ORDER BY col2 DESC ) AS a GROUP BY gid ORDER BY gid;
半連線方式:找不到比最大值還大的。
SELECT * FROM t2 a WHERE NOT EXISTS ( SELECT 1 FROM t2 b WHERE b.gid = a.gid AND b.col2 > a.col2 ) ORDER BY a.gid;
*N=3時:
自連線:
SELECT * FROM t2 a WHERE 3 > ( SELECT count(*) FROM t2 WHERE gid = a.gid AND col2 > a.col2 ) ORDER BY a.gid, a.col2 DESC;
半連線:
SELECT * FROM t2 a WHERE EXISTS ( SELECT count(*) FROM t2 b WHERE b.gid = a.gid AND a.col2 < b.col2 HAVING (count(*)) < 3 ) ORDER BY a.gid, a.col2 DESC
Oracle取每組的前N條記錄:可以使用分析函式,hive中也能使用
SELECT * FROM(
SELECT z.type , z.code ,ROW_NUMBER()
OVER(PARTITION BY z.type ORDER BY z.code desc) AS code_id
FROM group_info z
)
WHERE code_id <4; #取每組最大的前四條記錄
https://blog.csdn.net/kuodannie1668/article/details/79756964