08_MySQL的函数
08_MySQL的函數
一、介紹
概述:
? 在MySQL中,為了提高代碼重用性和隱藏實現細節,MySQL提供了很多函數。函數可以理解為別人封裝好的模板代碼。
分類:
? 在MySQL中,函數非常多,主要可以分為以下幾類:
- 聚合函數
- 數學函數
- 字符串函數
- 日期函數
- 控制流函數
- 窗口函數(MySQL8.0以上才有)
二、MySQL中的函數-聚合函數
1、概述
- 在MySQL中,聚合函數主要由:count,sum,min,max,avg,這些聚合函數我們之前都學過,不再重復。這里我們學習另外一個函數:group_concat(), 該函數用于實現行的合并。
- ==group_concat()==函數首先根據group by指定的列進行分組,并且用分隔符分隔,將同一個分組中的值連接起來,返回一個字符串結果。
格式:
groupe_concat([distinct] 字段名 [order by 排序字段 asc/desc] [separation '分隔符'])說明:
? (1)使用distinct可以排除重復值;
? (2)如果需要對結果中的值進行排序,可以使用order by子句;
? (3)separator是一個字符串值,默認為逗號。
2、使用方法
數據準備
create database if not exists mydb4; use mydb4; create table emp(emp_id int primary key auto_increment comment '編號',emp_name char(20) not null default '' comment '姓名',salary decimal(10,2) not null default 0 comment '工資',department char(20) not null default '' comment '部門' );insert into emp(emp_name,salary,department) VALUES ('張晶晶',5000,'財務部'),('王飛飛',5800,'財務部'),('趙剛',6200,'財務部'),('劉小貝',5700,'人事部'),('王大鵬',6700,'人事部'),('張小斐',5200,'人事部'),('劉云云',7500,'銷售部'),('劉云鵬',7200,'銷售部'),('劉云鵬',7800,'銷售部');操作:
-- 將所有員工的名字合并成一行 select group_concat(emp_name) from emp; -- 指定分隔符合并 select group_concat(emp_name separator ';') from emp; -- 指定排序方式和分隔符 select department,group_concat(emp_name order by salary desc separator ';') from emp group by department;三、MySQL中的函數-數學函數
1、介紹
| ABS(x) | 返回x的絕對值 | 返回-1的絕對值:select ABS(-1) --返回1 |
| CEIL(x) | 返回大于或等于x的最小整數 | select CEIL(-1) – 返回2 |
| FLOOR(x) | 返回小于或等于x的最大整數 | 小于或等于1.5的整數;select floor(1.5)-- 返回1 |
| greates(expr1,expr2,…) | 返回列表中的最大值 | 返回一下數字列表中的最大值:select greatest(3,12,34,8,25); – 34 返回以下字符串列表中的最大值:select greatest(“Google”,“Runoob”,“Apple”); – Runboob |
| least(expr1,expr2,…) | 返回列表中的最小值 | 返回以下數字列表中的最小值:select greatest(3,12,34,8,25); – 34 返回以下字符串列表中的最小值:select greatest(“Google”,“Runoob”,“Apple”); – Runboob |
| max(expression) | 返回字段expression中的最大值 | 返回數據表Products中字段Price的最大值:select max(price) as largestPrice from Products; |
| min(expression) | 返回字段expression中的最小值 | 返回數據表Products中字段Price的最大值:select min(price) as MinPrice from Products; |
| mod(x,y) | 返回x除以y以后的余數 | 5除以2的余數:select mod(5,2) – 1 |
| PI() | 返回圓周率(3.1315926) | select PI() – 3.1415926 |
| pow(x,y) | 返回x的y次方 | 2的3次方:select pow(2,3) – 8 |
| rand() | 返回0到1的隨機數 | select rand() -0.93099315644334 |
| round() | 返回離x最近的整數(遵循四舍五入) | select round(1.23456) – 1 |
| round(x,y) | 返回指定位數的小數(遵循四舍五入) | select round(1.23456,3) – 1.235 |
| truncate(x,y) | 返回數值x保留到小數點后y位的值(與round最大的區別是不會進行四舍五入) | select truncate(1.2345, 3) – 1.234 |
2、操作
-- 數學函數 -- 求絕對值 select abs(-10); select abs(10); select abs(表達式或字段) from 表; -- 向上取整 select ceil(1.1); -- 2 select ceil(1.0); -- 1 -- 向下取整 select floor(1.1); -- 1 select floor(1.9); -- 1 -- 取列表最大值 select greatest(1,2,3); -- 3 -- 取列表最小值 select least(1,2,3); -- 1 -- 取模 select mod(5,2); -- 1 -- 取x的y次方 select power(2,3); -- 8 -- 取隨機數 select rand(); select floor(rand() * 100); -- 取小數的四舍五入 select round(3.5415); -- 將小數的四舍五入取指定位置小數 select round(3.5415, 3); -- 3.542 -- 將小數直接截取到指定位數 select truncate(1.1415, 3); -- 1.141四、MySQL中的函數-字符串函數
1、介紹
| char_length(s) | 返回字符串s的字符數 | 返回字符串RUNOOB的字符數select char_length(“RUNOOB”) as lengthOfString; |
| character_length | 返回字符串s的字符數 | 返回字符串RUNOOB的字符數select character_length(“RUNOOB”) as lengthOfString; |
| concat(s1,s2,…sn) | 字符串s1,s2等多個字符串合并為一個字符串 | 合并多個字符串:select concat(“SQL”,“RUNOOB”,‘Google’,“Facebook”) as ConcatenatedString; |
| concat_ws(w,s1,s2,…sn) | 同concat(s1,s2,…)函數,但是每個字符串之間要加上x,x可以是分隔符 | 合并多個字符串,并添加分隔符,select concat_ws(“-”,“sql”,“Tutorial”) as ConcatenatedString; |
| field(s,s1,s2…) | 返回第一個字符串s在字符串列表(s1,s2…)中的位置 | 返回字符串c在列表值中的位置:select field (“c”,“a”,“b”,“c”,“d”); |
| ltrim(s) | 去掉字符串s開始處的空格 | 去掉字符串RUNOOB開始處的空格:select ltrim (’ runoob’) as leftTrim; – RUNOOB |
| MID(s,n,len) | 從字符串s的n位置截取長度為len的子字符串,同SUBSTRING(s,n,len) | 從字符串RUNOOB中的第二個位置截取3個字符:select mid(‘RUNOOB’,2,3) AS ExtractString; – UNO |
| position(s1 in s) | 從字符串s中獲取s1的開始位置 | 返回字符串abc中b的位置:select position (‘b’ in ‘abc’) ; – 2 |
| replace(s,s1,s2) | 將字符串s2替代字符串s中的字符串s1 | 將字符串abc中的字符a替換為字符x:select replace(‘abc’,‘a’, ‘x’); – xbc |
| reverse(s) | 將字符串s的順序反過來 | 將字符串abc的順序反過來:select reverse(‘abc’); – cba |
| right(s,n) | 返回字符串s的后n個字符 | 返回字符串runoob的后兩個字符:select right(‘runoob’,2); – ob |
| rtrim(s) | 去掉字符串s結尾處的空格 | 去掉字符串RUNOOB的末尾空格:select rtrim("RUNOOB ") as rightTrim; – RUNOOB |
| strcmp(s1,s2) | 比較字符串s1和s2,如果s1和s2相等返回0,如果s1>sc返回1,如果s1<s2返回-1 | 比較字符串:select strcmp(“runoob”,“runoob”); – 0 |
| substr(s,start,length) | 從字符串s的start位置截取長度為length的子字符串 | 從字符串RUNOOB中的第2個位置截取3個字符:select substr(“RUNOOB”,2,3) AS ExtractString; – UNO |
| substring(s,start,length) | 從字符串s的start位置截取長度為length的字符串 | 從字符串RUNOOB中的第2個位置截取3個字符:select substring(“RUNOOB”,2,3) AS ExtractString; – UNO |
| trim(s) | 去掉字符串s開始和結尾處的空格 | 去掉字符串RUNOOB的首尾空格:select trim(’ RUNOOB ') AS TrimmedString; |
| ucase(s) | 將字符串轉換為大寫 | 將字符串runoob轉換為大寫:select ucase(‘runoob’); – RUNOOB |
| upper(s) | 將字符串轉換為大寫 | 將字符串runoob轉換為大寫:select upper(‘runoob’); – RUNOOB |
| lcase(s) | 將字符串轉換為小寫 | 將字符串RUNOOB轉換為小寫:select upper(‘RUNOOB’); – runoob |
| lower(s) | 將字符串轉換為小寫 | 將字符串轉換為小寫將字符串RUNOOB轉換為小寫:select upper(‘RUNOOB’); – runoob |
2、操作
-- 字符串函數 -- 1.獲取字符串字符個數 select CHAR_LENGTH("hello"); -- 5 select char_length('你好嗎'); -- 3 -- length取長度,返回的單位是字節 select length('hello'); -- 5 select length('你好嗎'); -- 9 -- 2.字符串合并 select concat("hello", 'world'); select concat(c1,c2) from table_name; -- 3.指定分隔符進行字符串合并 select concat_ws('-','hello','world'); -- 4.返回字符串在列表中第一次出現的位置 select field('aaa','aaa','bbb','ccc'); -- 1 select field('bbb','aaa','bbb','ccc'); -- 2 -- 5.去除字符串空格 select ltrim(' aaaa'); -- 去除字符串左邊空格 select rtrim(' | aaa '); -- 去除字符串右邊空格 select trim(' aaa '); -- 去除字符串兩端空格 -- 6.字符串截取 select mid("helloworld", 2, 3); -- 從第二個字符開始截取,截取長度為3 -- 7.獲取字符串A在字符串中出現的位置 select position('abc'in 'helloabcworld'); -- 8.字符串替換 select replace('aaahelloaaaworld','aaa','bbb'); -- 9.字符串翻轉 select reverse('hello'); -- 10.返回字符串的后幾個字符 select right('hello',3); -- 返回最后三個字符 -- 11.字符串比較 select strcmp('hello','world'); -- 12.字符串截取 select substr('hello',2,3); -- 從第二個字符開始截取,截取三個字符 select substring('hello',2,3); -- 從第二個字符開始截取,截取三個字符 -- 13.將小寫轉大寫 select ucase('helloWorld'); -- HELLOWORLD select upper('helloWorld'); -- HEELOWORLD -- 14.將大寫轉為小寫 select lcase('helloWorld'); -- helloworld select lower('helloWorld'); -- helloworld 結合查詢案例:查出員工的雇傭年份和名字 select enamel,substr(hiredate,1,4) from emp;五、MySQL中的函數-日期函數
1、介紹
| unix_timestamp() | 返回從1970-01-01 00:00:00到當前毫秒值 | select unix_timestamp(); -->1632729059 |
| unix_timestamp(date_string) | 將指定日期轉為毫秒值時間戳 | select unix_timestamp(‘2021-12-07 13:01:03’); |
| from_unixtime(bigint unixtime[,stringformat]) | 將毫秒值時間戳轉為指定格式日期 | select from_unixtime(1598079966,‘%Y-%m-%d %H:%i:%s’);(1598079966, ‘%Y-%m-%d %H:%i:%s’); -->2020-08-22 15-06-06 |
| curdate() | 返回當前日期 | select curdate(); -->2018-09-19 |
| current_date() | 返回當前日期 | select curdate(); -->2018-09-19 |
| current_time() | 返回當前時間 | select current_time();–>19:59:02 |
| curtime() | 返回當前時間 | select curtime();–>19:59:02 |
| current_timestamp() | 返回當前日期和時間 | select current_timestamp();–>2018-09-19 20:57:43 |
| date() | 從日期或日期時間表達式中提取日期值 | select date(‘2017-06-15’);–>2017-06-15 |
| datediff(d1,d2) | 計算日期d1–>d2之間相隔的天數 | select datediff(‘2001-01-01’,‘2001-02-02’);–>-32 |
| timediff(time1,time2) | 計算時間差值 | select timediff(‘13:10:11’,“13:10:10”);–>00:00:01 |
| date_format(d,f) | 按表達式f的要求顯示日期d | select data_format(‘2011-11-11 11:11:11’, ‘%Y-%m-%d %r’);–>2011-11-11 11:11:11 AM |
| STR_TO_DATE(string, format_mask) | 將字符串轉變為日期 | select str_to_date(‘August 10 2017’, ‘%M %d % Y’);–>2017-08-10 |
| DATE_SUB(date,interval expr type) | 函數從日期減去指定的時間間隔 | Orders表中OrderDate字段減去2天:select OrderId, DATE_SUB(OrderDate,INTERVAL 2 DAY) AS OrderPayDate FROM Orders; |
| adddate/date_add(d, interval expr type) | 計算起始日期d加上一個時間段后的日期 type值可以是:microsecond, second, minute,hour,Day,week,month,quarter, year,day_minute,day_hour,year_month | select date_add(‘2017-06-15’, interva 10 day);–>2017-06-25 select date_add(‘2017-06-15 09:34:21’,interval 15 minute);–>2017-06-15 09:49:21 select date_add(‘2017-06-15 09:34:21’,interval -3 hour);–>2017-04-15 |
| extract(type from d) | 從日期d中獲取指定的值,type指定返回的值。type可以取值為microsecond, second, minute,hour… | select extract(minute from’2011-11-11 11:11:11’);–>11 |
| last_day(d) | 返回給定日期的那一月份的最后一天 | select last_day(‘2017-06-20’);–>2017-06-30 |
| makedate(year,day-of-year) | 基于給定參數年份year和所在年終的天數序號day-of-year返回一個日期 | select makedate(2017,3);–>2017-01-03 |
| year(d) | 返回年份 | select year(‘2017-06-15’);–>2017 |
| month(d) | 返回日期d中的月份至,1到12 | select month(‘2011-11-11 11:11:11’);–>11 |
| day(d) | 返回日期至d的日期部分 | select day(‘2017-06-15’);–>15 |
| hour(t) | 返回t中的小時值 | select hour(‘1:2:3’);–>1 |
| minute(d) | 返回t中的分鐘值 | select minute(‘1:2:3’);–>2 |
| second(t) | 返回t中的秒鐘值 | select second(‘1:2:3’);–>3 |
| quarter(d) | 返回日期d是第幾季節,返回1到4 | select quarter(‘2011-11-11 11:11:11’);–>4 |
| monthname(d) | 返回日期當中的月份名稱,如November | select monthname(‘2011-11-11 11:11:11’);–>November |
| month(d) | 返回日期d中的月份值,1到12 | select month(‘2011-11-11 11:11:11’);–>11 |
| dayname(d) | 返回日期d是星期幾,如Monday,Tuesday | select dayname(‘2011-11-11 11:11:11’);–>Friday |
| dayofmonth(d) | 計算日期d但是本月的第幾天 | select dayofmonth(‘2011-11-11 11:11:11’);–>11 |
| dayofweek(d) | 日期d今天是星期幾,1星期日,2星期1,以此類推 | select dayofweek(‘2011-11-11 11:11:11’);–>6 |
| dayofyear(d) | 計算日期d是本年的第幾天 | select dayofyear(‘2011-11-11 11:11:11’);–>315 |
| week(d) | 計算日期d是本年的第幾個星期,范圍是0到53 | select week(‘2011-11-11 11:11:11’);–>45 |
| weekday(d) | 日期d是星期幾,0表示星期一,1表示星期二 | select weekday('2017-06-15 ');–>3 |
| weekofyear(d) | 計算日期d是本年的第幾個星期,范圍是0到53 | select weekofyear(‘2011-11-11 11:11:11’);–>45 |
| yearweek(date,mode) | 返回年份及第幾周(0到53),mode中0表示周天,1表示周一,以此類推 | select weekday('2017-06-15 ');–>201724 |
| now() | 返回當期日期和時間 | select now()–>2018-09-19 20:57:43 |
2、時間格式
| %h | 小時(01-12) |
| %I | 小時(01-12) |
| %i | 分鐘,數值(00-59) |
| %J | 年的天(001-336) |
| %k | 小時(0-23) |
| %I | 小時(1-12) |
| %M | 月名 |
| %m | 月,數值(00-12) |
| %p | AM或PM |
| %r | 時間,12-小時(hh:mm:ss AM或PM) |
| %S | 秒(00-59) |
| %s | 秒(00-59) |
| %T | 時間,24-小時(hh:mm:ss) |
| %U | 周(00-53)星期日是一周的第一天 |
| %a | 編寫星期名 |
| %b | 編寫月名 |
| %c | 月,數值 |
| %D | 帶有英文前綴的月中的天 |
| %d | 月的天,數值(00-31) |
| %e | 月的天,數值(00-31) |
| %f | 微秒 |
| %H | 小時(00-23) |
| %u | 周(00-53)星期一是一周的第一天 |
| %V | 周(01-53)星期日是一周的第一天,與%X使用 |
| %v | 周(01-53)星期一是一周的第一天,與%x使用 |
| %W | 星期名 |
| %w | 周的天(0=星期日,6=星期六) |
| %X | 年,其中的星期日是周的第一天,4位,與%V使用 |
| %x | 年,其中的星期一是周的第一天,4位,與%v使用 |
| %Y | 年,4位 |
| %y | 年,2位 |
3、操作
-- 日期函數 -- 1.獲取時間戳 select UNIX_TIMESTAMP(); -- 2.將一個日期字符串轉為毫秒值 select UNIX_TIMESTAMP('2021-12-21 08:08:08'); -- 3.將時間戳毫秒值轉為指定格式的日期 select FROM_UNIXTIME(1640045288,'%Y-%m-%d %H:%i:%s'); -- 4.獲取當前的年月日 select curdate(); select CURRENT_DATE(); -- 5.獲取當前的時分秒 select CURRENT_TIME(); select curtime(); -- 6.獲取年月日和時分秒 select CURRENT_TIMESTAMP(); -- 7.從日期字符串中獲取年月日 select date('2022-12-12 12:34:56'); -- 8.獲取日期之間的差值(天數) select datediff('2021-12-23','2008-08-08'); select datediff(CURRENT_DATE(),'2008-08-08'); -- 9.獲取時間的差值(秒級) select timediff('12:12:34','10:18:56'); -- 01:53:38 -- 10.日期格式化 select date_format('2021-1-1 1:1:1', '%Y-%m-%d %H:%i:%s'); select date_format('2021-12-13 11:11:11','%Y-%m-%d %H:%i:%s'); -- 11.將字符串轉為日期 select str_to_date('2021-12-13 11:11:11','%Y-%m-%d %H:%i:%s'); -- 12.將日期進行減法 select date_sub('2021-10-01',interval 2 day); select date_sub('2021-10-01',interval 2 month); -- 13.將日期進行加法,-- 日期向后跳轉 select date_add('2021-10-01',interval 2 day); select date_add('2021-10-01',interval 2 month); -- 14.從日期中獲取小時 select extract(hour from '2021-12-13 11:12:13'); select extract(year from '2021-12-13 11:12:13'); select extract(month from '2021-12-13 11:12:13'); -- 15.獲取給定日期的最后一天(月內最后一天) select last_day('2021-08-13'); -- 16.獲取指定年份和天數的日期 select makedate('2021',53); -- 17.根據日期獲取年月日,時分秒 select year('2021-12-13 11:12:13'); -- 獲取年 select month('2021-12-13 11:12:13'); -- 獲取小時 select minute('2021-12-13 11:12:13'); -- 獲取分鐘 select quarter('2021-12-13 11:12:13'); -- 獲取季度 -- 18.根據日期獲取信息 select MONTHNAME('2021-12-13 11:12:13'); -- 獲取月份的英文 select dayname('2021-12-13 11:12:13'); -- 獲取周幾:Monday select dayofmonth('2021-12-13 11:12:13'); -- 當月的第幾天 select dayofweek('2021-12-13 11:12:13'); -- 1:周日 2:周一 select dayofyear('2021-12-13 11:12:13'); -- 獲取一年的第幾天select week('2021-12-13 11:12:13');六、MySQL中的函數-控制流函數
1、if邏輯判斷語句
?
| if(expr,v1,v2) | 如果表達式expr成立,返回結果v1;否則,返回結果v2 | select if(1>0,‘正確’,‘錯誤’);–>正確 |
| ifnull(v1,v2) | 如果v1的值不為null,則返回v1,否則返回v2. | select ifnull(null,‘Hello World’);–>Hello World |
| isnull(expr) | 判斷表達式是否為null | select isnull(null);–>1 |
| nullif(expr1,expr2) | 比較兩個字符串,如果字符串expr1與expr2相等,返回null,否則返回expr1 | select nullif(25,25);–>null |
操作
-- 控制流函數 -- if函數 select if(5>2,"大于","小于"); use mydb3; select *, if(score>=85,'優秀','及格') flag from score; -- ifnull函數 select ifnull(5,0); -- 5 select ifnull(null,0); -- 02、case when語句
格式:
case expression
? when condition1 then result1
? when condtion2 then result2
? …
? when condition3 then resultN
? else result
end
解釋:
case表示函數開始,end表示函數結束。如果condition1成立,則返回result1,如果condition2成立,則返回result2,當全部不成立則返回result,而當有一個成立之后,后面的就不執行了。
操作:
-- 案例1 select case 100 when 50 then 'tom' when 100 then 'mary' else 'tim' end; -- 案例2 select case when 1=2 then 'tom' when 2=2 then 'mary' else 'tim' end;-- case when語句 create database if not exists mydb4; use mydb4; -- 創建訂單表 create table orders(oid int primary key, -- 訂單idprice double, -- 訂單價格payType int -- 支付類型(1:微信支付 2:支付寶支付 3:銀行卡支付 4:其他) ); insert into orders values(1,1200,1); insert into orders values(2,1000,2); insert into orders values(3,200,3); insert into orders values(4,3000,1); insert into orders values(5,1500,2); insert into orders values(6,1500,5); -- case when操作案例 select *,case payType when 1 then '微信支付' when 2 then '支付寶支付' when 3 then '銀行卡支付' else '其他支付方式'end as payTypeStr from orders;七、MySQL中的函數-窗口函數
1、介紹
- MySQL8.0新增窗口函數,窗口函數又被稱為開窗函數,與Oracle窗口函數類似,屬于MySQL的一大特點。
- 非聚合窗口函數是相當于聚合函數來說的。聚合函數是對一組數據計算后返回單個值(即分組),非聚合函數一次只會處理一行數據。窗口聚合函數在行記錄上計算某個字段的結果是,可將窗口范圍內的數據輸入到聚合函數中,并不改變行數。
2、語法結構
window_function (expr) over(partition by ...order by ...frame_clause )其中,window_function是窗口函數的名稱;expr是參數,有些函數不需要參數;over子句包含三個選項:
-
分區(partition by)
partition by選項用于將數據行拆分成多個分區(組),它的作用類似于GROUP BY分組,如果省略了partition by,所有的數據作為一個組進行計算
-
排序(order by)
over子句中的order by選項用于指定分區內的排序方式,與order by子句的作用類似
-
以及窗口大小(frame_clause)
frame_clause選項用于在當前分區內指定一個計算窗口,也就是一個與當前行相關的數據子集。
3、窗口函數-序號函數
? 序號函數有三個:row_number(),rank(),dense_rank(),可以用來實現分組排序,并添加序號。這三個函數的排序規則有一點點不同。
- 格式
數據準備:
-- 窗口函數 use mydb4; create table if not exists employee(dname varchar(20), -- 部門名eid varchar(20), -- 員工編號ename varchar(20), -- 員工名字hiredate date, -- 入職日期salary double -- 薪資 ); insert into employee values('研發部','1001','劉備','2021-11-01',3000); insert into employee values('研發部','1002','關羽','2021-11-02',5000); insert into employee values('研發部','1003','張飛','2021-11-03',7000); insert into employee values('研發部','1004','趙云','2021-11-04',7000); insert into employee values('研發部','1005','馬超','2021-11-05',4000); insert into employee values('研發部','1006','黃忠','2021-11-06',4000);insert into employee values('銷售部','1007','曹操','2021-11-01',2000); insert into employee values('銷售部','1008','許褚','2021-11-02',3000); insert into employee values('銷售部','1009','典韋','2021-11-03',5000); insert into employee values('銷售部','1010','張遼','2021-11-04',6000); insert into employee values('銷售部','1011','徐晃','2021-11-05',9000); insert into employee values('銷售部','1012','曹洪','2021-11-06',6000);3.1、row_number()序號函數
? row_number() 序號不間斷,從1開始
- 操作
查詢結果:
研發部 張飛 7000 1
研發部 趙云 7000 2
研發部 關羽 5000 3
研發部 馬超 4000 4
研發部 黃忠 4000 5
研發部 劉備 3000 6
銷售部 徐晃 9000 1
銷售部 張遼 6000 2
銷售部 曹洪 6000 3
銷售部 典韋 5000 4
銷售部 許褚 3000 5
銷售部 曹操 2000 6
3.2、rank()序號函數
? rank() 序號間斷,從1開始
- 操作
查詢結果:
研發部 張飛 7000 1
研發部 趙云 7000 1
研發部 關羽 5000 3
研發部 馬超 4000 4
研發部 黃忠 4000 4
研發部 劉備 3000 6
銷售部 徐晃 9000 1
銷售部 張遼 6000 2
銷售部 曹洪 6000 2
銷售部 典韋 5000 4
銷售部 許褚 3000 5
銷售部 曹操 2000 6
3.3、dense_rank()序號函數
? dense_rank() 序號不間斷,條件相等時,序號重復
- 操作
查詢結果:
研發部 張飛 7000 1
研發部 趙云 7000 1
研發部 關羽 5000 2
研發部 馬超 4000 3
研發部 黃忠 4000 3
研發部 劉備 3000 4
銷售部 徐晃 9000 1
銷售部 張遼 6000 2
銷售部 曹洪 6000 2
銷售部 典韋 5000 3
銷售部 許褚 3000 4
銷售部 曹操 2000 5
3.4、案例2
-- 案例2:求出每個部門薪資排在前三名的員工-分組求TOPN select * from (select dname,ename,salary,DENSE_RANK() over(partition by dname order by salary desc) as rnfrom employee )t where t.rn <= 3;查詢結果:
研發部 張飛 7000 1
研發部 趙云 7000 1
研發部 關羽 5000 2
研發部 馬超 4000 3
研發部 黃忠 4000 3
銷售部 徐晃 9000 1
銷售部 張遼 6000 2
銷售部 曹洪 6000 2
銷售部 典韋 5000 3
3.5、案例3
-- 案例3:對所有員工進行全局排序(不分組) select dname,ename,salary,dense_rank() over (order by salary desc) as rn from employee;查詢結果:
銷售部 徐晃 9000 1
研發部 張飛 7000 2
研發部 趙云 7000 2
銷售部 張遼 6000 3
銷售部 曹洪 6000 3
研發部 關羽 5000 4
銷售部 典韋 5000 4
研發部 馬超 4000 5
研發部 黃忠 4000 5
研發部 劉備 3000 6
銷售部 許褚 3000 6
銷售部 曹操 2000 7
4、開窗聚合函數-sum,avg,max,min
4.1、概念
? 在窗口中每條記錄動態地應用聚合函數(sum(),avg(),max(),min(),count()),可以動態計算在指定窗口內的各種聚合函數值。
4.2、操作(以sum舉例,其他三個函數用法一樣)
4.2.1、案例1,分組又排序,分組內salary累加
select dname,ename,salary,sum(salary) over(partition by dname order by hiredate) as pv1 from employee;查詢結果
研發部 劉備 3000 3000
研發部 關羽 5000 8000
研發部 張飛 7000 15000
研發部 趙云 7000 22000
研發部 馬超 4000 26000
研發部 黃忠 4000 30000
銷售部 曹操 2000 2000
銷售部 許褚 3000 5000
銷售部 典韋 5000 10000
銷售部 張遼 6000 16000
銷售部 徐晃 9000 25000
銷售部 曹洪 6000 31000
4.2.2、案例2:如果沒有order by排序語句,默認把分組內的所有數據進行sum操作
select dname,ename,salary,sum(salary) over(partition by dname) as pv1 from employee;查詢結果:可根據結果,查出員工工資占部門總薪資的比例,比如(3000/30000)
研發部 劉備 3000 30000
研發部 關羽 5000 30000
研發部 張飛 7000 30000
研發部 趙云 7000 30000
研發部 馬超 4000 30000
研發部 黃忠 4000 30000
銷售部 曹操 2000 31000
銷售部 許褚 3000 31000
銷售部 典韋 5000 31000
銷售部 張遼 6000 31000
銷售部 徐晃 9000 31000
銷售部 曹洪 6000 31000
4.2.3、案例3:從分組內的開頭到結尾,進行累加(rows)
-- 案例3:從分組內的開頭到結尾,進行累加,unbounded-->開頭, preceding-->向前,current row-->當前行 select dname,ename,salary, sum(salary) over(partition by dname order by hiredate rows between unbounded preceding and current row) as pv1 from employee;查詢結果:相當于partition by + order by,與案例一結果一樣
4.2.4、案例4:從分組內,往前算三行+當前行,4行累加(rows)
-- 案例4:從分組內,當前行往前算三行,到當前行,4行累加 select dname,ename,salary, sum(salary) over(partition by dname order by hiredate rows between 3 preceding and current row) as pv1 from employee;查詢結果:
研發部 劉備 3000 3000
研發部 關羽 5000 8000
研發部 張飛 7000 15000
研發部 趙云 7000 22000 = 3000 + 5000+7000+7000(前三行+當前行)
研發部 馬超 4000 23000
研發部 黃忠 4000 22000
銷售部 曹操 2000 2000
銷售部 許褚 3000 5000
銷售部 典韋 5000 10000
銷售部 張遼 6000 16000
銷售部 徐晃 9000 23000
銷售部 曹洪 6000 26000
4.2.5、從分組內,往前3行+當前行+后1行,5行累加
-- 案例5:從分組內,往前算3行,包括當前行,再往后算1行,5行累加 select dname,ename,salary, sum(salary) over(partition by dname order by hiredate rows between 3 preceding and 1 following) as pv1 from employee;查詢結果:
研發部 劉備 3000 8000
研發部 關羽 5000 15000
研發部 張飛 7000 22000
研發部 趙云 7000 26000 = 3000+5000+7000+7000+4000
研發部 馬超 4000 27000
研發部 黃忠 4000 22000
銷售部 曹操 2000 5000
銷售部 許褚 3000 10000
銷售部 典韋 5000 16000
銷售部 張遼 6000 25000
銷售部 徐晃 9000 29000
銷售部 曹洪 6000 26000
5、窗口函數_分布函數-cume_dist和percent_rank
5.1、cump_dist
5.1.1、介紹
- 用途:分組內小于,等于當前rank值的行數/分組內總行數
- 應用場景:傳小于等于當前薪資(salary)的比例
5.1.2、操作
-- cume_dist() select dname,ename,salary, CUME_DIST() over(order by salary ) as pv1,CUME_DIST() over(partition by dname order by salary ) as pv2 from employee;查詢結果:
研發部 劉備 3000 0.25 0.16666666666666666
研發部 馬超 4000 0.4166666666666667 0.5
研發部 黃忠 4000 0.4166666666666667 0.5
研發部 關羽 5000 0.5833333333333334 0.6666666666666666
研發部 張飛 7000 0.9166666666666666 1
研發部 趙云 7000 0.9166666666666666 1
銷售部 曹操 2000 0.08333333333333333 0.16666666666666666
銷售部 許褚 3000 0.25 0.3333333333333333
銷售部 典韋 5000 0.5833333333333334 0.5
銷售部 張遼 6000 0.75 0.8333333333333334
銷售部 曹洪 6000 0.75 0.8333333333333334
銷售部 徐晃 9000 1 1
結果分析:
rn1:
? 第一條:3/12 = 1/4 = 0.25
? 第二條:5/12 = 0.4166666666666667
rn2:
? 第一條:1/6 = 0.1666666666666667
? 第二條:3/6 = 0.5
5.2、percent_rank
5.2.1、介紹
- 用途:每行按照公式(rank-1)/(rows-1)進行計算。其中,rank為rank()函數產生的序號,rows為當前窗口的記錄總行數
- 應用場景:不常用
5.2.2、操作
-- PERCENT_RANK() select dname,ename,salary, rank() over(partition by dname order by salary desc ) as pv1,percent_rank() over(partition by dname order by salary desc) as pv2 from employee;查詢結果:
研發部 張飛 7000 1 0
研發部 趙云 7000 1 0
研發部 關羽 5000 3 0.4
研發部 馬超 4000 4 0.6
研發部 黃忠 4000 4 0.6
研發部 劉備 3000 6 1
銷售部 徐晃 9000 1 0
銷售部 張遼 6000 2 0.2
銷售部 曹洪 6000 2 0.2
銷售部 典韋 5000 4 0.6
銷售部 許褚 3000 5 0.8
銷售部 曹操 2000 6 1
結果分析:
pv2:
? 第一行:(1-1)/(6-1) = 0
? 第二行:(1-1)/(6-1) = 0
? 第三行:(3-1)/(6-1) = 0.4
6、窗口函數_前后函數-lag和lead
6.1、介紹
- 用途:返回位于當前行的前n行(lag(expr,n))或后n行(lead(expr,n))的expr的值
- 應用場景:查詢前1名同學的成績和當前同學成績的差值
6.2、操作(以lag舉例,lead用法一樣)
第三個參數是默認值
-- lag select dname,ename,salary, hiredate,lag(hiredate,1,'2021-01-01') over( partition by dname order by hiredate desc ) as pv1,lag(hiredate,2) over(partition by dname order by hiredate desc) as pv2 from employee;查詢結果:
研發部 黃忠 4000 2021-11-06 2021-01-01
研發部 馬超 4000 2021-11-05 2021-11-06
研發部 趙云 7000 2021-11-04 2021-11-05 2021-11-06
研發部 張飛 7000 2021-11-03 2021-11-04 2021-11-05
研發部 關羽 5000 2021-11-02 2021-11-03 2021-11-04
研發部 劉備 3000 2021-11-01 2021-11-02 2021-11-03
銷售部 曹洪 6000 2021-11-06 2021-01-01
銷售部 徐晃 9000 2021-11-05 2021-11-06
銷售部 張遼 6000 2021-11-04 2021-11-05 2021-11-06
銷售部 典韋 5000 2021-11-03 2021-11-04 2021-11-05
銷售部 許褚 3000 2021-11-02 2021-11-03 2021-11-04
銷售部 曹操 2000 2021-11-01 2021-11-02 2021-11-03
結果分析:
pv1:
? 第一行:自身是第一行,前面沒數據,取默認值‘2021-01-01‘
? 第二行:取第一行的值
pv2:
? 第一行:前2行沒數據,取值null
? 第二行:前2行沒數據,取值null
? 第三行:前2行為第一行,有數據,取第一行的數據
7、窗口函數_首尾函數-first_value和last_value
7.1、介紹
- 用途:返回第一個(FIRST_VALUE(expr))或最后一個(LAST_VALUE(expr))expr的值
- 應用場景:截止到當前,按照日期排序查詢第1個入職和最后一個入職員工的薪資
7.2、操作
-- 窗口函數-頭尾函數 select dname,ename,salary, hiredate,FIRST_VALUE(salary) over( partition by dname order by hiredate) as first,LAST_VALUE(salary) over(partition by dname order by hiredate) as last from employee;查詢結果
研發部 劉備 3000 2021-11-01 3000 3000
研發部 關羽 5000 2021-11-02 3000 5000
研發部 張飛 7000 2021-11-03 3000 7000
研發部 趙云 7000 2021-11-04 3000 7000
研發部 馬超 4000 2021-11-05 3000 4000
研發部 黃忠 4000 2021-11-06 3000 4000
銷售部 曹操 2000 2021-11-01 2000 2000
銷售部 許褚 3000 2021-11-02 2000 3000
銷售部 典韋 5000 2021-11-03 2000 5000
銷售部 張遼 6000 2021-11-04 2000 6000
銷售部 徐晃 9000 2021-11-05 2000 9000
銷售部 曹洪 6000 2021-11-06 2000 6000
結果分析:
first_value取到目前行的第一行的值
last_value取到目前行的最后一行的值(本身)
8、窗口函數_其他函數-nth_value(expr,n)和ntile(n)
8.1、nth_value
8.1.1、介紹
- 用途:返回窗口中第n個expr的值。expr可以是表達式,也可以是列名
- 應用場景:截止到當前薪資,顯示每個員工的薪資中排名第2或者第3的薪資
8.1.2、操作
-- 窗口函數-其他函數 -- nth_value select dname,ename,salary, hiredate,nth_VALUE(salary,2) over( partition by dname order by hiredate) as second_value,nth_VALUE(salary,3) over(partition by dname order by hiredate) as thirth_value from employee;查詢結果:
研發部 劉備 3000 2021-11-01
研發部 關羽 5000 2021-11-02 5000
研發部 張飛 7000 2021-11-03 5000 7000
研發部 趙云 7000 2021-11-04 5000 7000
研發部 馬超 4000 2021-11-05 5000 7000
研發部 黃忠 4000 2021-11-06 5000 7000
銷售部 曹操 2000 2021-11-01
銷售部 許褚 3000 2021-11-02 3000
銷售部 典韋 5000 2021-11-03 3000 5000
銷售部 張遼 6000 2021-11-04 3000 5000
銷售部 徐晃 9000 2021-11-05 3000 5000
銷售部 曹洪 6000 2021-11-06 3000 5000
8.2、ntile
8.2.1、介紹
- 用途:將分區中的有序數據分為n個等級,記錄等級數
- 應用場景:將每個部門員工按照入職日期分成3組
8.2.2、操作
-- ntile -- 用途:將分區中的有序數據分為n個等級,記錄等級數 -- 案例1:將每個部門的員工按照入職日期分成3組 select dname,ename,salary, hiredate,ntile(3) over( partition by dname order by hiredate) as nt from employee;查詢結果:
研發部 劉備 3000 2021-11-01 1
研發部 關羽 5000 2021-11-02 1
研發部 張飛 7000 2021-11-03 2
研發部 趙云 7000 2021-11-04 2
研發部 馬超 4000 2021-11-05 3
研發部 黃忠 4000 2021-11-06 3
銷售部 曹操 2000 2021-11-01 1
銷售部 許褚 3000 2021-11-02 1
銷售部 典韋 5000 2021-11-03 2
銷售部 張遼 6000 2021-11-04 2
銷售部 徐晃 9000 2021-11-05 3
銷售部 曹洪 6000 2021-11-06 3
案例2:
-- 案例2:去除每個部門的第一組員工 select * from (select dname,ename,salary, hiredate,ntile(3) over( partition by dname order by hiredate) as ntfrom employee )t where t.nt = 1;查詢結果:
研發部 劉備 3000 2021-11-01 1
研發部 關羽 5000 2021-11-02 1
銷售部 曹操 2000 2021-11-01 1
銷售部 許褚 3000 2021-11-02 1
3000 5000
銷售部 曹洪 6000 2021-11-06 3000 5000
8.2、ntile
8.2.1、介紹
- 用途:將分區中的有序數據分為n個等級,記錄等級數
- 應用場景:將每個部門員工按照入職日期分成3組
8.2.2、操作
-- ntile -- 用途:將分區中的有序數據分為n個等級,記錄等級數 -- 案例1:將每個部門的員工按照入職日期分成3組 select dname,ename,salary, hiredate,ntile(3) over( partition by dname order by hiredate) as nt from employee;查詢結果:
研發部 劉備 3000 2021-11-01 1
研發部 關羽 5000 2021-11-02 1
研發部 張飛 7000 2021-11-03 2
研發部 趙云 7000 2021-11-04 2
研發部 馬超 4000 2021-11-05 3
研發部 黃忠 4000 2021-11-06 3
銷售部 曹操 2000 2021-11-01 1
銷售部 許褚 3000 2021-11-02 1
銷售部 典韋 5000 2021-11-03 2
銷售部 張遼 6000 2021-11-04 2
銷售部 徐晃 9000 2021-11-05 3
銷售部 曹洪 6000 2021-11-06 3
案例2:
-- 案例2:去除每個部門的第一組員工 select * from (select dname,ename,salary, hiredate,ntile(3) over( partition by dname order by hiredate) as ntfrom employee )t where t.nt = 1;查詢結果:
研發部 劉備 3000 2021-11-01 1
研發部 關羽 5000 2021-11-02 1
銷售部 曹操 2000 2021-11-01 1
銷售部 許褚 3000 2021-11-02 1
總結
以上是生活随笔為你收集整理的08_MySQL的函数的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 线性稳压器与开关稳压器的对比分析
- 下一篇: Expected single matc