1. 程式人生 > >MySQL在按照某個欄位分組、排序加序號

MySQL在按照某個欄位分組、排序加序號

#### 事情是這樣的,最近領導給了一個新的需求,要求在一張訂單表中統計每個人第一次和第二次購買的時間間隔,最後還需要按照間隔統計計數,求出中位數等資料。 - 由於MySQL不想Oracle那般支援行號、中位數等,所以怎麼在表中統計處資料成為了關鍵 #### 訂單表結構,主要包含欄位如下 - id、訂單號、購買人id、下單時間、商品資訊欄位、購買人資訊欄位等 #### 1.為了方便後續統計,我的想法是構建了一張中間表,只儲存一些關鍵欄位,如購買人id,下單時間,訂單號,以及購買的第幾次,結構如下圖: ![](https://img2020.cnblogs.com/blog/2184019/202101/2184019-20210109125844056-809654415.png) ##### 欄位解釋:fans_id:購買人id、order_time:下單時間、tid:訂單號、series:商品系列、shop:店鋪、times:第幾次購買、sync_time:同步時間、effective:是否有效、failure_time:失效時間 #### 2.寫了一段程式碼,處理歷史訂單,把所有資料按照表中格式新增進去,方便統計,每次新訂單進來時,更新一下這個表即可。 #### 3.統計: ``` -- 統計購買次數最大和最小 select max(times) from 統計表 where effective = '有效' -- 統計最大購買次數間隔、最小間隔以及平均間隔(中位數的話,由於MySQL沒有中位數函式,所以可以利用子查詢的SQL通過程式程式碼計算) SELECT max(date) as max, min(date) as min, sum( date * mans ) / count( mans ) as avg FROM ( SELECT ifnull(datediff( a.order_time, ( SELECT order_time FROM 統計表 WHERE times = 次數1 AND effective = '有效' AND a.fans_id = fans_id ) ),0) AS date, a.fans_id, 1 AS mans FROM 統計表 a WHERE a.times = 次數2 AND effective = '有效' ) t ``` #### 4.由於接收訂單後,可能狀態會變,無法確保次數準確,更新統計表中每個人的次數SQL如下: ``` UPDATE (SELECT @rownum:=@rownum+1 as rn,id,fans_id,order_time from (SELECT id,fans_id,order_time from 統計表 where fans_id = 購買人 and effective = '有效' ORDER BY order_time asc) h, (SELECT @rownum:=0) t) t1, statistics_repurchase t2 set t2.times=t1.rn where t2.id=t1.id; ``` #### 5.由於需求還需要支援按照商品系列查詢,所以需要在該表基礎之上建立臨時表以作統計,滿足**==MySQL在按照某個欄位分組、排序加序號==** 第一版SQL如下: ``` SELECT a.fans_id, a.order_time, a.sync_time, count( * ) AS times FROM 統計表 AS a, 統計表 AS b WHERE a.fans_id = b.fans_id AND a.order_time >= b.order_time AND a.effective = '有效' AND b.effective = '有效' AND a.series LIKE concat('%','系列','%') AND b.series LIKE concat('%','系列','%') GROUP BY a.fans_id, a.id -- 按照購買人id,按照購買時間進行排序,並標記序號,加上建立表語句如下(建表時需加索引,方便後續查詢): CREATE TABLE 臨時表名 ( id INT PRIMARY KEY AUTO_INCREMENT, fans_id VARCHAR ( 32 ), order_time datetime, sync_time date, times INT ( 6 ), PRIMARY KEY ( id ), INDEX mid_fans_id ( fans_id ) USING BTREE, INDEX mid_order_time ( order_time ) USING BTREE, INDEX mid_times ( times ) USING BTREE, INDEX mid_sync_time ( sync_time ) USING BTREE ) AS ( SELECT a.fans_id, a.order_time, a.sync_time, count( * ) AS times FROM 統計表 AS a, 統計表 AS b WHERE a.fans_id = b.fans_id AND a.order_time >= b.order_time AND a.effective = '有效' AND b.effective = '有效' AND a.series LIKE concat('%','系列','%') AND b.series LIKE concat('%','系列','%') GROUP BY a.fans_id, a.id ); -- 由於資料庫版本為5.4,所以建完臨時表不支援一條sql多次查詢,沒辦法,只能直接建立表 ``` #### 結果如圖: ![](https://img2020.cnblogs.com/blog/2184019/202101/2184019-20210109132246923-2093429027.png) #### 滿足了排序,但是後來我發現有一些人是同時間下單的,以至於某些人的times是重複的,於是更新為下面的SQL ``` SELECT a.fans_id, a.order_time, a.sync_time, ( @i := CASE WHEN @pre_keyword = fans_id THEN @i + 1 ELSE 1 END ) AS times, @pre_keyword:=fans_id FROM ( SELECT fans_id, order_time, sync_time FROM 統計表 WHERE effective = '有效' AND series LIKE concat('%','系列','%') ORDER BY fans_id,order_time ) a, ( SELECT @i := 0, @pre_keyword := '' ) AS b ``` #### 這次的sql是按照時間排序後,判斷當前購買人第幾次出現,打上序號,由此滿足需求 #### 查詢結果和上圖相同,就不附圖了哈 #### 效率這,購買人id,下單時間需要建立索引,否則可能有些慢,測試庫中資料大概七百萬左右,總體查詢可在四秒內完成 ### 希望這篇文章能在開發中給予您一定的幫助,新人部落格主,碼齡一年,如有更好的方案,望