【實戰分享】相同組獲取第一條資料的幾種SQL實現
阿新 • • 發佈:2020-12-30
技術標籤:sqldbjavasqldb資料庫java相同組獲取第一條資料
【實戰分享】相同組獲取第一條資料的幾種SQL實現
- 分組排序後獲取第一條資料
- 分組加行號後獲取第一條資料(當然獲取前幾條資料也是同理)
- 利用GROUP BY後聚合函式,比如:MAX, MIN等
此種方式簡單粗暴,存在一個隱藏問題,就是非分組列獲取值不一定是同一行的資料,比如:這裡的
workout_time
此種方式適用於MariaDB,如果想適用於MySQL需要修改ANY_VALUE(wr.workout_date)
,存在非分組列相同問題
SELECT
h.id AS 'hospital_id' , h.name AS 'hospital_name', p.id AS 'patient_id', p.name AS 'patient_name',
ed.game_id, g.name AS 'game_name', MAX(ed.score) AS 'game_score', wr.workout_date AS 'workout_time'
FROM
t_p p,
t_w_r wr,
t_e_d ed,
t_h h,
t_g g
WHERE
p.name = 'kenny' AND
p.id = wr.patient_id
AND wr.id = ed.workout_id
AND p.hospital_id = h.id
AND ed.game_id = g.id
GROUP BY p.id, p.name, ed.game_id, workout_time
ORDER BY game_id, game_score DESC;
- ROW_NUMBER() OVER(PARTITION BY [fields] ORDER BY [fields]) AS ‘row_num’
此種方式適用於MariaDB,不適用在低版本MySql,聽說8.0以上支援
SELECT * from (
SELECT ROW_NUMBER() OVER(PARTITION BY p.id, p.name, ed.game_id ORDER BY game_id, game_score DESC) AS 'row_num',
h.id AS 'hospital_id', h.name AS 'hospital_name', p.id AS 'patient_id', p.name AS 'patient_name', p.gender,
ed.game_id, g.name AS 'game_name', g.limb, ed.score AS 'game_score', wr.workout_date AS 'workout_time'
FROM
t_p p,
t_w_r wr,
t_e_d ed,
t_h h,
t_g g
WHERE
-- p.name = 'kenny' and
ed.game_id = 28 and
workout_date >= '2019-09-11' and
p.id = wr.patient_id
AND wr.id = ed.workout_id
AND p.hospital_id = h.id
AND ed.game_id = g.id
ORDER BY game_id, game_score DESC
) t
WHERE row_num = 1
SET @row_number = 0; SELECT @row_number:=IF(@pre_game_id = game_id, @row_number + 1, 1) AS 'row_num', @pre_game_id:=game_id AS 'game_id2', t.*
FROM WHERE row_num = 1
此種方式適用於MySQL,但是,在MariaDB中使用需要解決一個問題,明明子查詢已經排序再設定行號,但是就是設定行號的時候不是按照排序後的,可以說行號設定在排序前進行了,因此出來的結果同一個分組同時存在幾條
row_num = 1
的情況
經試驗後,確定MariaDB需要加入GROUP BY方可分組排序後才能正確新增行號
SET @row_number = 0;
另外,這句不加,如果在Client第一次執行會出現行號都是1的情況
經試驗後,是因為@pre_game_id
沒有初始值,而@row_number
可以沒有初始值
SET @row_number = 0;
SELECT * FROM (
SELECT @row_number:=IF(@pre_game_id = game_id, @row_number + 1, 1) AS 'row_num', t.*, @pre_game_id:=game_id AS 'game_id2' FROM (
SELECT
h.id AS 'hospital_id', h.name AS 'hospital_name', p.id AS 'patient_id', p.name AS 'patient_name', p.gender,
ed.game_id, g.name AS 'game_name', g.limb, ed.score AS 'game_score', wr.workout_date AS 'workout_time'
FROM
t_p p,
t_w_r wr,
t_e_d ed,
t_h h,
t_g g
WHERE
p.name = 'kenny' AND
workout_date >= '2010-09-11' AND
p.id = wr.patient_id
AND wr.id = ed.workout_id
AND p.hospital_id = h.id
AND ed.game_id = g.id
-- MySQL 不需要此 GROUP BY,加了會報錯 this is incompatible with sql_mode=only_full_group_by
GROUP BY game_id, game_score, workout_time
ORDER BY game_id, game_score DESC, workout_time DESC
) t
) m
WHERE
row_num = 1
-- MariaDB 不需要此 ORDER BY,加了也沒關係
ORDER BY game_id
注意:
- 如果以上試驗有錯誤或跟實際情況有出入,請試驗正確後採用
- 如果考慮資料庫效能,也可以根據業務需要拆分到程式中實現
- 不建議一開始就在程式中寫N多步驟的程式碼才東拼西湊,還不如簡單粗暴一個SQL實現效能棒
©Kenny Fang