MySQL自定义排序函数FIELD()
轉載自:https://blog.csdn.net/lxz3000/article/details/6173873
MySQL可以通過field()函數自定義排序
格式:
field(value,str1,str2,str3,str4)
value與str1、str2、str3、str4比較,返回1、2、3、4,如遇到null或者不在列表中的數據則返回0. 這個函數好像Oracle中沒有專門提供(也可能是我沒有用到),不過自己實現這樣一個函數還是比較簡單的。
mysql> select * from driver_log order by name;+--------+-------+------------+-------+ | rec_id | name | trav_date | miles | +--------+-------+------------+-------+ | 1 | Ben | 2006-08-30 | 152 | | 9 | Ben | 2006-09-02 | 79 | | 5 | Ben | 2006-08-29 | 131 | | 8 | Henry | 2006-09-01 | 197 | | 6 | Henry | 2006-08-26 | 115 | | 4 | Henry | 2006-08-27 | 96 | | 3 | Henry | 2006-08-29 | 300 | | 10 | Henry | 2006-08-30 | 203 | | 7 | Suzi | 2006-09-02 | 502 | | 2 | Suzi | 2006-08-29 | 391 | +--------+-------+------------+-------+10 rows in set (0.00 sec) mysql> select * from driver_log order by field(name,'Suzi','Ben','Henry');+--------+-------+------------+-------+ | rec_id | name | trav_date | miles | +--------+-------+------------+-------+ | 2 | Suzi | 2006-08-29 | 391 | | 7 | Suzi | 2006-09-02 | 502 | | 1 | Ben | 2006-08-30 | 152 | | 9 | Ben | 2006-09-02 | 79 | | 5 | Ben | 2006-08-29 | 131 | | 8 | Henry | 2006-09-01 | 197 | | 6 | Henry | 2006-08-26 | 115 | | 4 | Henry | 2006-08-27 | 96 | | 3 | Henry | 2006-08-29 | 300 | | 10 | Henry | 2006-08-30 | 203 | +--------+-------+------------+-------+10 rows in set (0.00 sec) mysql> select * from driver_log order by field(name,'Suzi','Ben');+--------+-------+------------+-------+ | rec_id | name | trav_date | miles | +--------+-------+------------+-------+ | 10 | Henry | 2006-08-30 | 203 | | 8 | Henry | 2006-09-01 | 197 | | 6 | Henry | 2006-08-26 | 115 | | 4 | Henry | 2006-08-27 | 96 | | 3 | Henry | 2006-08-29 | 300 | | 7 | Suzi | 2006-09-02 | 502 | | 2 | Suzi | 2006-08-29 | 391 | | 5 | Ben | 2006-08-29 | 131 | | 9 | Ben | 2006-09-02 | 79 | | 1 | Ben | 2006-08-30 | 152 | +--------+-------+------------+-------+10 rows in set (0.00 sec) mysql> select * from driver_log order by field(name,'Suzi','Ben') desc;+--------+-------+------------+-------+ | rec_id | name | trav_date | miles | +--------+-------+------------+-------+ | 1 | Ben | 2006-08-30 | 152 | | 9 | Ben | 2006-09-02 | 79 | | 5 | Ben | 2006-08-29 | 131 | | 2 | Suzi | 2006-08-29 | 391 | | 7 | Suzi | 2006-09-02 | 502 | | 8 | Henry | 2006-09-01 | 197 | | 6 | Henry | 2006-08-26 | 115 | | 4 | Henry | 2006-08-27 | 96 | | 3 | Henry | 2006-08-29 | 300 | | 10 | Henry | 2006-08-30 | 203 | +--------+-------+------------+-------+10 rows in set (0.00 sec)20180911更新內容:
我們都非常習慣通過 MySQL 的 IN 函數來查詢特定集合的數據,比如為了在 books 表中找出李雷、韓梅梅和安華寫的書,我們可以有如下的 SQL:
SELECT * FROM books WHERE `books`.`author` IN ('李雷','韓梅梅','安華');數據庫返回如下結果:
| 安華 | 暴走漫畫 |
| 李雷 | 藍色生死戀 |
| 韓梅梅 | 冰與火之歌 |
| 韓梅梅 | 天國的階梯 |
| 李雷 | 這個殺手不太冷 |
| 韓梅梅 | 阿甘正傳 |
雖然這樣確實能夠返回所有李雷、韓梅梅和安華寫過的書,但是返回的數據的排序方式是默認按照數據在數據庫中的存儲順序,假如我們需要的返回結果是同時按照 IN 查詢條件里邊的參數順序來排序呢?這個時候我們就需要利用到 MySQL FIELD 這個函數了,FIELD 函數本來是 MySQL 提供用來查詢某一個字符串在給定字符串元組中的索引位置的,比如這個官方例子:
SELECT FIELD('ej', 'Hej', 'ej', 'Heja', 'hej', 'foo'); # -> 2如果將其應用在 ORDER BY 排序條件中,就可以根據指定字段的值在給定參數列表中的索引數值,進而將查詢結果按照參數列表排序了
SELECT * FROM books WHERE `books`.`author` IN ('李雷','韓梅梅','安華') ORDER BY FIELD(author, '李雷','韓梅梅','安華');| 李雷 | 藍色生死戀 |
| 李雷 | 這個殺手不太冷 |
| 韓梅梅 | 冰與火之歌 |
| 韓梅梅 | 天國的階梯 |
| 韓梅梅 | 阿甘正傳 |
| 安華 | 暴走漫畫 |
可以發現,這一次,我們得到的結果就是按照條件參數列表 ‘李雷’,’韓梅梅’,’安華’ 進行排序后得到了。
應用層面的思考
1. 兼容性
本文提到的 FIELD 函數,畢竟只是 MySQL 數據庫內置提供的一種函數,除非你非常明確你的項目就是只用 MySQL 數據庫,否則,你的 SQL 代碼在未來遷移到其他數據庫的過程中就會遇到語法兼容性問題(只是 PostgreSQL 數據庫不支持 FIELD)。
2. 性能問題
我們都知道,數據庫在進行 ORDER BY 排序的時候,除非它是按照某個已經存在索引的鍵的值進行排序,否則數據庫則需要通過計算 ORDER BY 中表達式的值并且按照查詢結果建立新的臨時表,這個過程會帶來額外的時間開銷跟內存開銷,對數據庫本身就是一種性能負擔。這樣的方式在單一數據庫多個數據庫客戶端連接的時候,可能對數據庫造成太大負擔。
3. 與應用層代碼的結合
盡管使用 FIELD 函數可能帶來兼容性以及性能方面的隱患,但是 FIELD 的使用并非全是有損之處。
比如在與 Ruby 的 active_record 結合時,這種通過數據庫直接完成排序等 SQL 語句可以方便我們構建 ActiveRecord::Relation 對象,因為我們不再需要先將查詢結果集從內存中轉為數組排序,再進行二次查詢,可以幫助我們減少 N+1 查詢問題,后者也是常見的影響數據庫服務器性能的現象之一。除此之外,這樣的寫法也可以有效地幫助我們簡化代碼,保持代碼簡潔。
但是在不需要對數據進行二次查詢或者查詢數據量太大的情況下,我反而建議可以通過 Ruby 的 Array#sort_by 方法對數據進行排序,這樣的話,排序的任務就轉移給了客戶端代碼,排序任務的壓力就自然分散,減輕了服務器端的壓力。
總結
在確認項目數據庫不大可能為 MySQL 之外的數據庫的前提下,查詢數據量少或者需要保持業務代碼簡潔的場景下,我建議可以采用 FIELD 函數排序;而在數據量龐大的情況下,或者不大可能出現大量 N+1 查詢的情況下,我建議可以采用先在數據庫中查詢數據集(只查詢 IN 條件,不排序)再到內存中通過業務代碼排序(比如 Ruby 的 Array#sort_by)的方式。
總結
以上是生活随笔為你收集整理的MySQL自定义排序函数FIELD()的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: MySQL ceil()函数
- 下一篇: Mac平台下安装与配置MySQL