MySQL自定义变量和排序的使用--以查询每个分类的最高销量商品为例


前言

今天在工作中遇到了MySQL数据库的自定义变量,可以用于实现类Oracle数据库的rownum一级其他一些更复杂的功能。

一、背景

MySQL的自定义变量是一种用户可以定义和修改的变量。自定义变量的名称以@符号开头,例如@myvar。自定义变量可以存储一个值,也可以存储一个表达式的结果。通过不同的表达式,可以为每一条数据都生产不同的自定义数据。比如Oracle中的rownum等。

二、场景

假如有商品销量表,结构如下:

列名中文名
id主键id
name商品名称
type商品类型
sales商品销量

需求:查询每个类别销量最高的一种商品的名称和销量。

三.准备工作

使用如下SQL进行创建表和测试数据的插入:

-- 创建表
CREATE TABLE Products (
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(255) NOT NULL,
    type VARCHAR(255) NOT NULL,
    sales INT NOT NULL
);

-- 插入测试数据
INSERT INTO Products (name, type, sales) VALUES
('Product 1', 'Type A', 100),
('Product 2', 'Type A', 200),
('Product 3', 'Type B', 150),
('Product 4', 'Type B', 250),
('Product 5', 'Type C', 75),
('Product 6', 'Type C', 175),
('Product 7', 'Type A', 225),
('Product 8', 'Type B', 300),
('Product 9', 'Type C', 80),
('Product 10', 'Type A', 90);

四.解决方案

查询SQL如下:

SELECT result.id, result.name, result.type, result.sales FROM (
    SELECT 
        products.*,
        @rownum := IF(@prev_type = type, @rownum + 1, 1) AS rn,
        @prev_type := type
    FROM
        (SELECT * FROM Products ORDER BY type, sales DESC) as products,
        (SELECT @rownum := 0, @prev_type := '') as vars
) as result
WHERE result.rn = 1;

具体思路为
1.从products表中查询需要的商品名称、类型、销量等数据,并按照类型、销量排序,保证每种类型的商品在结果中都是相邻的。

(SELECT * FROM Products ORDER BY type, sales DESC) as products

2.使用自定义数据,记为@rownum,@prev_type,其中@rownum表示记录的行号初始默认为0,而@prev_type表示上一条查询记录的商品类型,初始默认null。然后与products的查询结果进行(隐式)连接,即给products的每条查询结果都添加了初始的@rownum和@prev_type。该部分的查询单独执行结果为:

SELECT 
        *
    FROM
        (SELECT * FROM Products ORDER BY type, sales DESC) as products,
        (SELECT @rownum := 0, @prev_type := '') as vars

查询的结果为:

idnametypesales@rownum :=0@prev_type := “”
7Product 7Type A2250
2Product 2Type A2000
1Product 1Type A1000
10Product 10Type A900
8Product 8Type B3000
4Product 4Type B2500
3Product 3Type B1500
6Product 6Type C1750
9Product 9Type C800
5Product 5Type C750

3.在外层的查询中, 因为已经按找类型进行了排序,因此在结果中,type相同的数据行必定相邻,可以在每一条记录中进行检查。我们首先检查自定义变量@prev_type的值是否和本条记录,如果相同,那么我们吧@rownum+1作为记录的行号,否则说明记录已经来到了新的类型,我们将@rownum归零,重新从1开始计算.这样就可以得到每种类型的商品在自己所属的类型内按销量先行排序的结果。

SELECT 
        products.*,
        @rownum := IF(@prev_type = type, @rownum + 1, 1) AS rn,
        @prev_type := type
    FROM
        (SELECT * FROM Products ORDER BY type, sales DESC) as products,
        (SELECT @rownum := 0, @prev_type := '') as vars

查询的结果如下:

idnametypesalesrn@prev_type := “”
7Product 7Type A2251Type A
2Product 2Type A2002Type A
1Product 1Type A1003Type A
10Product 10Type A904Type A
8Product 8Type B3001Type B
4Product 4Type B2502Type B
3Product 3Type B1503Type B
6Product 6Type C1751Type C
9Product 9Type C802Type C
5Product 5Type C753Type C

4.最后只要在结果中筛选rn=1的记录,即可得到每种商品类型内销量为第一的商品

SELECT result.id, result.name, result.type, result.sales FROM (
    SELECT 
        products.*,
        @rownum := IF(@prev_type = type, @rownum + 1, 1) AS rn,
        @prev_type := type
    FROM
        (SELECT * FROM Products ORDER BY type, sales DESC) as products,
        (SELECT @rownum := 0, @prev_type := '') as vars
) as result
WHERE result.rn = 1;

查询结果为:

idnametypesales
7Product 7Type A225
8Product 8Type B300
6Product 6Type C175

总结

本文以查询不同类型商品的最高销量记录为例简单介绍了MySQL
中自定义数据的使用。实际生产中,可以根据不同需要定制SQL,也可以根据场所的需要选择其他更符合需求的数据库。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值