mysql踩坑之limit与sum函数混合使用问题详解

前言

今天同事在同步完订单数据后,由于订单总金额和数据源的总金额存在差异,选择使用LIMIT和SUM()函数计算当前分页的总金额来和对方比较特定订单的总金额,却发现计算出来的金额并不是分页的订单总金额,而是所有订单的总金额。

数据库版本为mysql 5.7,下面会用一个示例复盘遇到的问题。

问题复盘

本次复盘会用一个很简单的订单表作为示例。

数据准备

订单表建表语句如下(这里偷懒了,使用了自增ID,实际开发中不建议使用自增ID作为订单ID)

CREATE TABLE `order` (
 `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '订单ID',
 `amount` decimal(10,2) NOT NULL COMMENT '订单金额',
 PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

插入金额为100的SQL如下(执行10次即可)

INSERT INTO `order`(`amount`) VALUES (100);

所以总金额为10*100=1000。

问题SQL

使用limit对数据进行分页查询,同时使用sum()函数计算出当前分页的总金额

SELECT
  SUM(`amount`)
FROM
  `order`
ORDER BY `id`
LIMIT 5;

前面也提到了运行的结果,期待的结果应该为5*100=500,然而实际运行的结果却为1000.00(带有小数点是因为数据类型)

问题排查

其实如果对SELECT语句执行顺序有一定了解的朋友可以很快确定为什么返回的结果为所有的订单总金额?下面我会就问题SQL的执行书序来分析问题:

  1. FROM:FROM子句是最先执行的,确定了查询的是order这张表
  2. SELECT:SELECT子句是第二个执行的子句,同时SUM()函数也在此时执行了。
  3. ORDER BY:ORDER BY子句是第三个执行的子句,其处理的结果只有一个,就是订单总金额
  4. LIMIT:LIMIT子句是最后执行的,此时结果集中只有一个结果(订单总金额)

补充内容

这里补充一下SELECT语句执行顺序

  1. FROM <left_table>
  2. ON <join_condition>
  3. <join_type> JOIN <right_table>
  4. WHERE <where_condition>
  5. GROUP BY <group_by_list>
  6. HAVING <having_condition>
  7. SELECT
  8. DISTINCT <select_list>
  9. ORDER BY <order_by_condition>
  10. LIMIT <limit_number>

解决办法

遇到需要统计分页数据时(除了SUM()函数外,常见的COUNT()、AVG()、MAX()、MIN()函数也存在这个问题),可以选择使用子查询来处理(PS:这里不考虑内存计算,针对的是使用数据库解决这个问题)。上面的问题解决方案如下:

SELECT
  SUM(o.amount)
FROM
  (SELECT
    `amount`
  FROM
    `order`
  ORDER BY `id`
  LIMIT 5) AS o;

运行的返回值为500.00。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对我们的支持。

(0)

相关推荐

  • mysql优化limit查询语句的5个方法

    mysql的分页比较简单,只需要limit offset,length就可以获取数据了,但是当offset和length比较大的时候,mysql明显性能下降 1.子查询优化法 先找出第一条数据,然后大于等于这条数据的id就是要获取的数据 缺点:数据必须是连续的,可以说不能有where条件,where条件会筛选数据,导致数据失去连续性,具体方法请看下面的查询实例: 复制代码 代码如下: mysql> set profiling=1; Query OK, 0 rows affected (0.00

  • Mysql中limit的用法方法详解与注意事项

    在我们使用查询语句的时候,经常要返回前几条或者中间某几行数据,这个时候怎么办呢?不用担心, mysql已经为我们提供了这样一个功能. SELECT * FROM table  LIMIT [offset,] rows | rows OFFSET offset LIMIT 子句可以被用于强制 SELECT 语句返回指定的记录数.LIMIT 接受一个或两个数字参数.参数必须 是一个整数常量.如果给定两个参数,第一个参数指定第一个返回记录行的偏移量,第二个参数指定返回 记录行的最大数目.初始记录行的偏

  • MySQL中的SUM函数使用教程

    MySQL的SUM函数是用来找出记录中各种的字段的总和. 要了解SUM函数考虑EMPLOYEE_TBL表具有以下记录: mysql> SELECT * FROM employee_tbl; +------+------+------------+--------------------+ | id | name | work_date | daily_typing_pages | +------+------+------------+--------------------+ | 1 | Jo

  • Mysql中的count()与sum()区别详细介绍

    首先创建个表说明问题 复制代码 代码如下: CREATE TABLE `result` ( `name` varchar(20) default NULL, `subject` varchar(20) default NULL, `score` tinyint(4) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=utf8 插入一些数据, 复制代码 代码如下: insert into result values ('张三','数学',90), ('张三'

  • 深入分析Mysql中limit的用法

    Mysql中limit的用法:在我们使用查询语句的时候,经常要返回前几条或者中间某几行数据,这个时候怎么办呢?不用担心,mysql已经为我们提供了这样一个功能. SELECT * FROM table   LIMIT [offset,] rows | rows OFFSET offset LIMIT 子句可以被用于强制 SELECT 语句返回指定的记录数.LIMIT 接受一个或两个数字参数.参数必须是一个整数常量.如果给定两个参数,第一个参数指定第一个返回记录行的偏移量,第二个参数指定返回记录行

  • mysql delete limit 使用方法详解

    mysql delete limit优点: 用于DELETE的MySQL唯一的LIMIT row_count选项用于告知服务器在控制命令被返回到客户端前被删除的行的最大值.本选项用于确保一个DELETE语句不会占用过多的时间.您可以只重复DELETE语句,直到相关行的数目少于LIMIT值为止. 如果DELETE语句包括一个ORDER BY子句,则各行按照子句中指定的顺序进行删除.此子句只在与LIMIT联用是才起作用.例如,以下子句用于查找与WHERE子句对应的行,使用timestamp_colu

  • 详解MySQL的limit用法和分页查询语句的性能分析

    limit用法 在我们使用查询语句的时候,经常要返回前几条或者中间某几行数据,这个时候怎么办呢?不用担心,mysql已经为我们提供了这样一个功能. SELECT * FROM table LIMIT [offset,] rows | rows OFFSET offset LIMIT 子句可以被用于强制 SELECT 语句返回指定的记录数.LIMIT 接受一个或两个数字参数.参数必须是一个整数常量.如果给定两个参数,第一个参数指定第一个返回记录行的偏移量,第二个参数指定返回记录行的最大数目.初始记

  • mysql中sum float类型使用小数点的方法

    方法一:最好的办法是将float字段改为decimal(16,6).具体方法:可设置一个临时字段,结合MySQL的关键字binary进行准确复制等.方法二:使用binary关键字解决.具体操作为"select sum(binary 字段名(float类型))"BINARY不是函数,是类型转换运算符,它用来强制它后面的字符串为一个二进制字符串例子: 复制代码 代码如下: "select sum(a.number*binary(b.price)) as total       

  • MYSQL中有关SUM字段按条件统计使用IF函数(case)问题

    今天群里有人问了个问题是这样的:  然后有群友是这样回答的 复制代码 代码如下: select name,sum(case when stype=4 then money*(-1) else money end ) as M from table group by name 我想了想,应该可以用IF函数 于是改了下 复制代码 代码如下: select name,sum(money*IF(stype=4,-1,1)) as M from table group by name 两种方式那种更效率还

  • MySql中取前几行数据使用limit来完成

    在mysql中是没有top关键字的,在mysql中可以用limit来完成功能. order by id desc limit 10 按照id的倒序排序 取出前10条 order by id desc limit 0,10 按照id的倒序排序 取出前10条 order by id limit 5,10 按照id的正序排序 从第5条开始取10条 复制代码 代码如下: SELECT cat_id FROM shop_goods_type order by cat_id desc limit 1

随机推荐