group by搭配 order by解決排序問題


問題

Ftravel_id Facct_no Froute_code Fmodify_time
41010020180725102219102000010452 1359c027b0a15266418643239300118 4101001701E214 2018-07-25 10:22:19
41010020180725102749102000010453 1359c027b0a15266418643239300118 4101001701E214 2018-07-25 10:27:49
41010020180725103059102000010455 1359c027b0a15266418643239300119 4101001701E214 2018-07-25 10:30:59

這里的問題是如何得到指定時間范圍內,指定 Facct_no 用戶的 limit 個行程信息,返回行程序列按時間排序,且序列中每個 Froute_code 值都是唯一的,如果重復則取最新的一個。

因為 distinct 和 group by 都可以用來去重,這里總結下:

  • group by & distinct 的使用和區別
  • 去重時排序

去重 group by & distinct

group by 語句

GROUP BY 語句根據一個或多個列對結果集進行分組。在分組的列上我們可以使用 COUNT, SUM, AVG,等函數。

SELECT column_name, aggregate_function(column_name)
FROM table_name
WHERE column_name operator value
GROUP BY column_name

在 MySQL 中,不加聚合函數的情況下,返回的結果是分組后每組結果集中的第一行;選擇的字段不必在 GROUP BY 中存在。

SELECT Ftravel_id,Facct_no FROM db_ccm_cx.t_ride_record_201807
GROUP BY Froute_code

對於標准 SQL 而言,GROUP BY 一定要結合聚合函數使用,而且選擇的字段除了聚合函數外,還必須在 GROUP BY 中出現。如以下 SQL 語句:

SELECT Froute_code,count(Facct_no) FROM db_ccm_cx.t_ride_record_201807
GROUP BY Froute_code

如果在SELECT語句中使用GROUP BY子句,而不使用聚合函數,則GROUP BY子句的行為與DISTINCT子句類似。

SELECT Froute_code FROM db_ccm_cx.t_ride_record_201807
GROUP BY Froute_code

GROUP BY X意思是將所有具有相同X字段值的記錄放到一個分組里;

多列情況下,GROUP BY X, Y意思是將所有具有相同X字段值和Y字段值的記錄放到一個分組里,也就是其中一個值不一樣都會影響分組結果。

這里利用 group by 進行去重的原理是,不加聚合函數的情況下,返回的結果是分組后每組結果集中的第一行,這里是根據要去重的列進行分組的;比如按照 Froute_code 進行去重,則 SQL 是:

SELECT * FROM db_ccm_cx.t_ride_record_201807
GROUP BY Froute_code

返回的結果是分組后每組結果集中的第一行,導致重復 Froute_code 的行程信息可能會返回 Fmodify_time 較老的一條,我們是想返回重復 Froute_code 中最近的一條,Mysql 的 GROUP BY 沒有排序功能。如果這樣子呢:

SELECT * FROM db_ccm_cx.t_ride_record_201807
GROUP BY Froute_code ORDER BY Fmodify_time 

增加 ORDER BY Fmodify_time,也沒法實現去除的較老的,返回較新的 Froute_code 行程信息。因為 GROUP BY 會比 ORDER BY 先執行,沒有辦法在 GROUP BY 的各個 group 中進行針對某一列的排序。

只要在 GROUP BY 前將順序調整好,把你希望的數據排在最前面,那么 GROUP BY 時就能順利取到這個數據。故解決方法就是先進行你想要的排序,然后在此排序后的結果集的基礎上,進行 GROUP BY 操作。比如下面 SQL:

SELECT * 
FROM
(SELECT * FROM db_ccm_cx.t_ride_record_201807 ORDER BY Fmodify_time ) temp_table
GROUP BY Froute_code

另外,如果對輸出的結果,想要排序的字段和 GROUP BY 字段一樣,可以使用

[GROUP BY {col_name | expr | position}
      [ASC | DESC], ... [WITH ROLLUP]]

比如,按照 Froute_code 進行排序:

SELECT * 
FROM db_ccm_cx.t_ride_record_201807
GROUP BY Froute_code ASC

這個和顯式使用 ORDER BY Froute_code ASC 含義一樣,但 GROUP BY 在 ORDER BY 前進行,因此也無法實現對 GROUP BY 的各個 group 中進行針對某一列的排序。

distinct

關鍵詞 DISTINCT 用於返回唯一不同的值。語法是:SELECT DISTINCT 列名稱 FROM 表名稱,比如以下 SQL:

SELECT DISTINCT Company FROM Orders 

多列情況下,distinct 和 group by 一樣,也是同時作用在了多個字段,多個字段組合一起不同的都會作為返回結果。比如以下 SQL:

SELECT DISTINCT Company,OrderPrice  FROM Orders 

如果想返回多列,網上有一種錯誤的說法(見https://www.cnblogs.com/peijie-tech/p/3457777.html):因為 DISTINCT 單獨使用如果不放在前面會報錯,與其他函數使用時候,沒有位置限制,所以可以使用下面 SQL,這樣的返回結果多了一列無用的count數據:

SELECT Company, OrderPrice , COUNT(DISTINCT Company) FROM Orders 

在 MYSQL 5.6 上是不行的,始終只返回 1列;

因此如果想返回多列,最好使用 group by 代替。

SELECT Company, OrderPrice  FROM Orders  GROUP BY Company

如果列具有NULL值,並且對該列使用DISTINCT子句,MySQL將保留一個NULL值,並刪除其它的NULL值,因為DISTINCT子句將所有NULL值視為相同的值。
可以使用具有聚合函數(例如SUM,AVG和COUNT)的DISTINCT子句中,在MySQL將聚合函數應用於結果集之前刪除重復的行。

SELECT COUNT(DISTINCT Company) FROM Orders 

如果要將DISTINCT子句與LIMIT子句一起使用,MySQL會在查找LIMIT子句中指定的唯一行數時立即停止搜索。

SELECT DISTINCT state FROM customers WHERE state IS NOT NULL LIMIT 3;

參考鏈接

https://segmentfault.com/a/1190000006821331
https://www.cnblogs.com/peijie-tech/p/3457777.html
https://www.yiibai.com/mysql/distinct.html
https://blog.csdn.net/PIGer920/article/details/7006420
https://blog.csdn.net/qbg19881206/article/details/8648991
https://dev.mysql.com/doc/refman/8.0/en/group-by-optimization.html
https://dev.mysql.com/doc/refman/5.5/en/select.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM