博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
MySQL取每组的前N条记录
阅读量:5861 次
发布时间:2019-06-19

本文共 9395 字,大约阅读时间需要 31 分钟。

 

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 aWHERE    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,    valFROM    t bINNER JOIN (    SELECT        *    FROM        t a    WHERE    ORDER BY        val DESC) a ON a.id = b.idGROUP BY    a.idORDER BY    id;

 

二.实例:取每组最大的前 N条          

CREATE TABLE t2 (    id INT PRIMARY KEY,    gid CHAR,    col1 INT,    col2 INT) ENGINE = INNODB;INSERT INTO t2VALUES    (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 aGROUP BY    gidORDER BY    gid;

 

半连接方式:找不到比最大值还大的。

SELECT    *FROM    t2 aWHERE    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 aWHERE    3 > (        SELECT            count(*)        FROM            t2        WHERE            gid = a.gid        AND col2 > a.col2    )ORDER BY    a.gid,    a.col2 DESC;

 

半连接:

SELECT    *FROM    t2 aWHERE    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_idFROM group_info z)WHERE code_id <4;   #取每组最大的前四条记录

https://blog.csdn.net/kuodannie1668/article/details/79756964

 

转载于:https://www.cnblogs.com/softidea/p/10268811.html

你可能感兴趣的文章
2016-04-16 拿到一个offer
查看>>
linux使用nfs、portmap服务共享远程磁盘的方法
查看>>
sklearn 快速入门 - 0.18 中文翻译
查看>>
tomcat显示中文页面
查看>>
linux下lnmp网站搭建
查看>>
wget整站下载
查看>>
《转》ceilometer的数据采集机制入门
查看>>
VS使用技巧——工欲善其事必先利其器
查看>>
conn /as sysdba 详解
查看>>
试卷: 阿里巴巴2016前端开发工程师笔试(一)
查看>>
交换机端口安全总结
查看>>
PHP 无极限分类 之非递归实现
查看>>
HAproxy指南之haproxy实现动静分离(案例篇)
查看>>
修正后的SYSTEM_THREADS与SYSTEM_PROCESSES结构体
查看>>
图解OSPF从入门到配置
查看>>
Android窗口机制(三)Window和WindowManager的创建与Activity
查看>>
2016上海
查看>>
让IDEA生成链式编程风格的类
查看>>
mongoDB 入门指南、示例
查看>>
进攻型病毒攻击Tumblr博客
查看>>