-
1 # 茶鋪裡的水
-
2 # 數通暢聯
MySQL中內建函式無外乎就那麼幾類,共分為字元函式、數值函式、比較函式、流程控制函式、日期函式、聚合函式及資訊函式七大類。字元函式是最常用的一種函式,在一個具體應用中通常會綜合幾個甚至幾類函式來實現字串處理。在字元函式中最常用的有兩種CONCAT和REPLACE,CONCAT將多個字串連線成一個字串,REPLACE替換字串。
數值型函式主要是對數值型資料進行處理,對前端客戶錄入資料進行反編譯等,得到我們想要的結果,其中最為常用的包含GREATEST、RAND,GREATEST返回集合中最大的值,RAND生成隨機數。
比較函式是對資料進行篩選時所使用的常用函式,其中最為常用的有BETWEEN...AND...篩選欄位引數為某兩個區間的資料,IN篩選出在列出值範圍內的資料,NULL進行NULL判斷。
流程控制類函式可以進行條件操作,用來實現SQL的條件邏輯,允許開發者將一些應用程式業務邏輯轉換到資料庫後臺,最為常用的函式IFNULL如果arg1不是空,返回arg1,否則返回arg2,CASE WHEN對資料進行判斷,樣例SELECT CASE WHEN 1>0 THEN "TRUE" ELSE "FALSE" END,當1>0時結果為TRUE反之為FASLE。
MySQL對於日期的處理方式相對來講還是較為全面的,內建了很多有關日期的處理的函式,例如DAY、MONTH、YEAR等。其中較為常用的NOW()獲取當前系統年月日時間,還有獲取當前年、月、日、季度函式等。DATE_ADD根據日期進行相加,DATEDIFF兩個日期進行相減,DATE_FORMAT將時間轉換成字串等。
聚合函式又稱組函式,一般情況下,我們需要的聚合資料(總和、平均數、最大值、最小值)等並不總是儲存在表中,但是我們可以透過執行聚合函式來獲取它。COUNT用來統計數量,SUM對資料進行彙總求和,AVG用來求平均值,GROUP_CONCAT將分組的資料進行展示,該函式返回帶有來自一個組的連線的非NULL 值的字串結果。
資訊函式主要是對系統資訊進行檢視例如獲取資料庫版本號資訊、連線ID、獲取當前資料庫、最後插入記錄的ID及當前的使用者資訊進行檢視。其中較為常用的VERSION、DATABASE、USER等。
查詢技巧:MySQL查詢技巧主要是對Select語句進行最佳化。
1. 對查詢進行最佳化,應儘量避免全表掃描,首先應考慮在 where 及 order by 涉及的列上建立索引。
2. 不要在 where 子句中的“=”左邊進行函式、算術運算或其他表示式運算,否則系統將可能無法正確使用索引。
3. 索引並不是越多越好,索引固然可 以提高相應的 select 的效率,但同時也降低了 insert 及 update 的效率,因為 insert 或 update 時有可能會重建索引,所以怎樣建索引需要慎重考慮,視具體情況而定。一個表的索引數最好不要超過6個,若太多則應考慮一些不常使用到的列上建的索引是否有必要。
4. 任何地方都不要使用 select * from t ,用具體的欄位列表代替*,不要返回用不到的任何欄位。
6. 儘量避免向客戶端返回大資料量,若資料量過大,應該考慮相應需求是否合理。
7. 應儘量避免在 where 子句中使用!=或<>運算子,否則引擎將放棄使用索引而進行全表掃描。
8. in和 not in 也要慎用,否則會導致全表掃描。
以上是個人平日總結的,可以進行參考,很多東西還是要在實際的專案中多使用,積累經驗,熟能生巧。
-
3 # 愛可生雲資料庫
一直以來,MySQL 只有針對聚合函式的彙總類功能,比如MAX, AVG 等,沒有從 SQL 層針對聚合類每組展開處理的功能。不過 MySQL 開放了 UDF 介面,可以用 C 來自己寫UDF,這個就增加了功能行難度。
這種針對每組展開處理的功能就叫視窗函式,有的資料庫叫分析函式。
在 MySQL 8.0 之前,我們想要得到這樣的結果,就得用以下幾種方法來實現:
1. session 變數
2. group_concat 函式組合
3. 自己寫 store routines
接下來我們用經典的 學生/課程/成績 來做視窗函式演示
準備
學生表
mysql> show create table student \G*************************** 1. row ***************************Table: studentCreate Table: CREATE TABLE student (sid int(10) unsigned NOT NULL,sname varchar(64) DEFAULT NULL,PRIMARY KEY (sid)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci1 row in set (0.00 sec)課程表
mysql> show create table course\G*************************** 1. row ***************************Table: courseCreate Table: CREATE TABLE `course` (`cid` int(10) unsigned NOT NULL,`cname` varchar(64) DEFAULT NULL,PRIMARY KEY (`cid`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci1 row in set (0.00 sec)成績表
mysql> show create table score\G*************************** 1. row ***************************Table: scoreCreate Table: CREATE TABLE `score` (`sid` int(10) unsigned NOT NULL,`cid` int(10) unsigned NOT NULL,`score` tinyint(3) unsigned DEFAULT NULL,PRIMARY KEY (`sid`,`cid`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci1 row in set (0.00 sec)測試資料
mysql> select * from student;+-----------+--------------+| sid | sname |+-----------+--------------+| 201910001 | 張三 || 201910002 | 李四 || 201910003 | 武松 || 201910004 | 潘金蓮 || 201910005 | 菠菜 || 201910006 | 楊發財 || 201910007 | 歐陽修 || 201910008 | 郭靖 || 201910009 | 黃蓉 || 201910010 | 東方不敗 |+-----------+--------------+10 rows in set (0.00 sec)mysql> select * from score;;+-----------+----------+-------+| sid | cid | score |+-----------+----------+-------+| 201910001 | 20192001 | 50 || 201910001 | 20192002 | 88 || 201910001 | 20192003 | 54 || 201910001 | 20192004 | 43 || 201910001 | 20192005 | 89 || 201910002 | 20192001 | 79 || 201910002 | 20192002 | 97 || 201910002 | 20192003 | 82 || 201910002 | 20192004 | 85 || 201910002 | 20192005 | 80 || 201910003 | 20192001 | 48 || 201910003 | 20192002 | 98 || 201910003 | 20192003 | 47 || 201910003 | 20192004 | 41 || 201910003 | 20192005 | 34 || 201910004 | 20192001 | 81 || 201910004 | 20192002 | 69 || 201910004 | 20192003 | 67 || 201910004 | 20192004 | 99 || 201910004 | 20192005 | 61 || 201910005 | 20192001 | 40 || 201910005 | 20192002 | 52 || 201910005 | 20192003 | 39 || 201910005 | 20192004 | 74 || 201910005 | 20192005 | 86 || 201910006 | 20192001 | 42 || 201910006 | 20192002 | 52 || 201910006 | 20192003 | 36 || 201910006 | 20192004 | 58 || 201910006 | 20192005 | 84 || 201910007 | 20192001 | 79 || 201910007 | 20192002 | 43 || 201910007 | 20192003 | 79 || 201910007 | 20192004 | 98 || 201910007 | 20192005 | 88 || 201910008 | 20192001 | 45 || 201910008 | 20192002 | 65 || 201910008 | 20192003 | 90 || 201910008 | 20192004 | 89 || 201910008 | 20192005 | 74 || 201910009 | 20192001 | 73 || 201910009 | 20192002 | 42 || 201910009 | 20192003 | 95 || 201910009 | 20192004 | 46 || 201910009 | 20192005 | 45 || 201910010 | 20192001 | 58 || 201910010 | 20192002 | 52 || 201910010 | 20192003 | 55 || 201910010 | 20192004 | 87 || 201910010 | 20192005 | 36 |+-----------+----------+-------+50 rows in set (0.00 sec)mysql> select * from course;+----------+------------+| cid | cname |+----------+------------+| 20192001 | mysql || 20192002 | oracle || 20192003 | postgresql || 20192004 | mongodb || 20192005 | dble |+----------+------------+5 rows in set (0.00 sec)MySQL 8.0 之前
比如我們求成績排名前三的學生排名,我來舉個用 session 變數和 group_concat 函式來分別實現的例子:
session 變數方式
每組開始賦一個初始值序號和初始分組欄位。
SELECTb.cname,a.sname,c.score, c.ranking_scoreFROMstudent a,course b,(SELECTc.*,IF(@cid = c.cid,@rn := @rn + 1,@rn := 1) AS ranking_score,@cid := c.cid AS tmpcidFROM(SELECT*FROMscoreORDER BY cid,score DESC) c,(SELECT@rn := 0 rn,@cid := "") initialize_table) cWHERE a.sid = c.sidAND b.cid = c.cidAND c.ranking_score <= 3ORDER BY b.cname,c.ranking_score;+------------+-----------+-------+---------------+| cname | sname | score | ranking_score |+------------+-----------+-------+---------------+| dble | 張三 | 89 | 1 || dble | 歐陽修 | 88 | 2 || dble | 菠菜 | 86 | 3 || mongodb | 潘金蓮 | 99 | 1 || mongodb | 歐陽修 | 98 | 2 || mongodb | 郭靖 | 89 | 3 || mysql | 李四 | 100 | 1 || mysql | 潘金蓮 | 81 | 2 || mysql | 歐陽修 | 79 | 3 || oracle | 武松 | 98 | 1 || oracle | 李四 | 97 | 2 || oracle | 張三 | 88 | 3 || postgresql | 黃蓉 | 95 | 1 || postgresql | 郭靖 | 90 | 2 || postgresql | 李四 | 82 | 3 |+------------+-----------+-------+---------------+15 rows in set, 5 warnings (0.01 sec)group_concat 函式方式
利用 findinset 內建函式來返回下標作為序號使用。
SELECT*FROM(SELECTb.cname,a.sname,c.score,FIND_IN_SET(c.score, d.gp) score_rankingFROMstudent a,course b,score c,(SELECTcid,GROUP_CONCAT(scoreORDER BY score DESC SEPARATOR ",") gpFROMscoreGROUP BY cidORDER BY score DESC) dWHERE a.sid = c.sidAND b.cid = c.cidAND c.cid = d.cidORDER BY d.cid,score_ranking) yttWHERE score_ranking <= 3;+------------+-----------+-------+---------------+| cname | sname | score | score_ranking |+------------+-----------+-------+---------------+| dble | 張三 | 89 | 1 || dble | 歐陽修 | 88 | 2 || dble | 菠菜 | 86 | 3 || mongodb | 潘金蓮 | 99 | 1 || mongodb | 歐陽修 | 98 | 2 || mongodb | 郭靖 | 89 | 3 || mysql | 李四 | 100 | 1 || mysql | 潘金蓮 | 81 | 2 || mysql | 歐陽修 | 79 | 3 || oracle | 武松 | 98 | 1 || oracle | 李四 | 97 | 2 || oracle | 張三 | 88 | 3 || postgresql | 黃蓉 | 95 | 1 || postgresql | 郭靖 | 90 | 2 || postgresql | 李四 | 82 | 3 |+------------+-----------+-------+---------------+15 rows in set (0.00 sec)MySQL 8.0 視窗函式
MySQL 8.0 後提供了原生的視窗函式支援,語法和大多數資料庫一樣,比如還是之前的例子:
用 row_number() over () 直接來檢索排名。
mysql>SELECT*FROM(SELECTb.cname,a.sname,c.score,row_number() over (PARTITION BY b.cnameORDER BY c.score DESC) score_rankFROMstudent AS a,course AS b,score AS cWHERE a.sid = c.sidAND b.cid = c.cid) yttWHERE score_rank <= 3;+------------+-----------+-------+------------+| cname | sname | score | score_rank |+------------+-----------+-------+------------+| dble | 張三 | 89 | 1 || dble | 歐陽修 | 88 | 2 || dble | 菠菜 | 86 | 3 || mongodb | 潘金蓮 | 99 | 1 || mongodb | 歐陽修 | 98 | 2 || mongodb | 郭靖 | 89 | 3 || mysql | 李四 | 100 | 1 || mysql | 潘金蓮 | 81 | 2 || mysql | 歐陽修 | 79 | 3 || oracle | 武松 | 98 | 1 || oracle | 李四 | 97 | 2 || oracle | 張三 | 88 | 3 || postgresql | 黃蓉 | 95 | 1 || postgresql | 郭靖 | 90 | 2 || postgresql | 李四 | 82 | 3 |+------------+-----------+-------+------------+15 rows in set (0.00 sec)那我們再找出課程 MySQL 和 DBLE 裡不及格的倒數前兩名學生名單。
mysql>SELECT*FROM(SELECTb.cname,a.sname,c.score,row_number () over (PARTITION BY b.cidORDER BY c.score ASC) score_rankingFROMstudent AS a,course AS b,score AS cWHERE a.sid = c.sidAND b.cid = c.cidAND b.cid IN (20192005, 20192001)AND c.score < 60) yttWHERE score_ranking < 3;+-------+--------------+-------+---------------+| cname | sname | score | score_ranking |+-------+--------------+-------+---------------+| mysql | 菠菜 | 40 | 1 || mysql | 楊發財 | 42 | 2 || dble | 武松 | 34 | 1 || dble | 東方不敗 | 36 | 2 |+-------+--------------+-------+---------------+4 rows in set (0.00 sec)到此為止,我們只是演示了row_number() over() 函式的使用方法,其他的函式有興趣的朋友可以自己體驗體驗,方法都差不多。
回覆列表
mysql常用的函式包括數學函式,字串函式,日期相關函式,加密函式等,你挨個嘗試一下應該都能掌握了。至於查詢技巧,你可以建幾個表嘗試一下left join,inner join,union all等,嘗試一下行轉列,列轉行,嘗試一下分頁查詢的寫法。
總之,很多東西還是要在實際的專案中多用,自然就能熟練,也不必著急。