在使用分組函數時, 進行結果集篩選, 遇到的一些問題以及解決方案【推薦:mysql影片教學】
1. 應用程式場景
有兩張表格
文章表(一對多留言表) t_posts:
oid, posts_name
留言表(多對一文章表) t_comment:
oid, posts_id, msg_content, create_time
2.需求分析
查詢每篇文章的最新回覆內容3.SQL寫
select tp.oid, tp.posts_name, tc.msg_content, tc.create_time from t_posts tp left join t_comment tc on tp.oid = tc.posts_id group by tp.oid having create_time = max(create_time)
登入後複製
#假設現在有兩個文章A, B (回應的記錄在資料庫的順序與下述一致)
<p>A有一个回复记录时间为: 2019-09-10 <br>A有一个回复记录时间为: 2019-09-11 <br>B有一个回复记录时间为: 2019-09-01 <br>B有一个回复记录时间为: 2019-09-09<br></p>
登入後複製
所以分組之後的結果集只會取每則留言的第一筆作為分組之後的記錄資訊, 這時如果使用having create_time = max(create_time)
那麼, max(create_time) 為目前分組的最大時間
所以上述sql會遺失結果集
4.改造SQL
因為知道分組之後合併的重複結果集為rownum最小的那條, 那麼可不可以改造sql如下??select tp.oid, tp.posts_name, tc.msg_content, tc.create_time from t_posts tp left join t_comment tc on tp.oid = tc.posts_id group by tp.oid having create_time = max(create_time) -- 下面的是新增的sql order by tc.create_time desc
登入後複製
後來想想可不可以不用having, 直接用order by來優化分組後的結果呢?
having create_time = max (create_time)
select tp.oid, tp.posts_name, tc.msg_content, tc.create_time from t_posts tp left join t_comment tc on tp.oid = tc.posts_id group by tp.oid order by tc.create_time desc
登入後複製
5.終極改造版本
因為order by 只能後影響group by, 那麼是不是可以在group by 之前先把結果集排序一下, 然後再分組呢?select * from ( select tp.oid, tp.posts_name, tc.msg_content, tc.create_time from t_posts tp left join t_comment tc on tp.oid = tc.posts_id order by tc.create_time desc ) t group by t.oid
登入後複製
- 在子查詢裡使用limit 99999
- 在子查詢裡使用where條件, create_time = (select max(create_time) from t_comment group by oid)
-
select * from ( select tp.oid, tp.posts_name, tc.msg_content, tc.create_time from t_posts tp left join t_comment tc on tp.oid = tc.posts_id order by tc.create_time desc limit 9999 ) t group by t.oid
登入後複製
大功告成
附加知識點:mysql5.5 與mysql 5.7 版本差異: 5.7 版本, 如果不使用limit, group by 會把order by 最佳化掉#