mysql踩坑記錄之limit和sum函數混合使用問題

前言

今天同事在同步完訂單數據後,因爲訂單總金額和數據源的總金額存在差別,選擇使用LIMITSUM()函數計算當前分頁的總金額來和對方比較特定訂單的總金額,卻發現計算出來的金額並非分頁的訂單總金額,而是全部訂單的總金額。mysql

數據庫版本爲mysql 5.7,下面會用一個示例覆盤遇到的問題。sql

問題覆盤

本次覆盤會用一個很簡單的訂單表做爲示例。數據庫

數據準備

訂單表建表語句以下(這裏偷懶了,使用了自增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;

插入金額爲100SQL以下(執行10次便可)code

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

因此總金額爲10*100=1000內存

問題SQL

使用limit對數據進行分頁查詢,同時使用sum()函數計算出當前分頁的總金額ci

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

前面也提到了運行的結果,期待的結果應該爲5*100=500,然而實際運行的結果卻爲1000.00(帶有小數點是由於數據類型)開發

問題排查

其實若是對SELECT語句執行順序有必定了解的朋友能夠很快肯定爲何返回的結果爲全部的訂單總金額?下面我會就問題SQL的執行書序來分析問題:同步

  1. FROMFROM子句是最早執行的,肯定了查詢的是order這張表
  2. SELECTSELECT子句是第二個執行的子句,同時SUM()函數也在此時執行了。
  3. ORDER BYORDER BY子句是第三個執行的子句,其處理的結果只有一個,就是訂單總金額
  4. LIMITLIMIT子句是最後執行的,此時結果集中只有一個結果(訂單總金額)

補充內容

這裏補充一下SELECT語句執行順序it

  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

相關文章
相關標籤/搜索