MySQL在按照某個字段分組、排序加序號

事情是這樣的,最近領導給了一個新的需求,要求在一張訂單表中統計每一個人第一次和第二次購買的時間間隔,最後還須要按照間隔統計計數,求出中位數等數據。

  • 因爲MySQL不想Oracle那般支持行號、中位數等,因此怎麼在表中統計處數據成爲了關鍵

訂單表結構,主要包含字段以下

  • id、訂單號、購買人id、下單時間、商品信息字段、購買人信息字段等

1.爲了方便後續統計,個人想法是構建了一張中間表,只存儲一些關鍵字段,如購買人id,下單時間,訂單號,以及購買的第幾回,結構以下圖:

字段解釋: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以下:mysql

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屢次查詢,沒辦法,只能直接建立表

結果如圖:

知足了排序,可是後來我發現有一些人是同時間下單的,以致於某些人的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,下單時間須要建立索引,不然可能有些慢,測試庫中數據大概七百萬左右,整體查詢可在四秒內完成

但願這篇文章能在開發中給予您必定的幫助,新人博客主,碼齡一年,若有更好的方案,望指教!

相關文章
相關標籤/搜索