MySQL在按照某個欄位分組、排序加序號
阿新 • • 發佈:2021-01-09
#### 事情是這樣的,最近領導給了一個新的需求,要求在一張訂單表中統計每個人第一次和第二次購買的時間間隔,最後還需要按照間隔統計計數,求出中位數等資料。
- 由於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,下單時間需要建立索引,否則可能有些慢,測試庫中資料大概七百萬左右,總體查詢可在四秒內完成
### 希望這篇文章能在開發中給予您一定的幫助,新人部落格主,碼齡一年,如有更好的方案,望