(二)SQL 函数篇

SQL 函数

函数是指一段可以直接被另外一段程序调用的程序或代码。

  • 字符串函数
  • 数值函数
  • 数据类型转换函数
  • 日期函数
  • 流程函数
  • 窗口函数

1.字符串函数

常用函数:

函数功能
CONCAT(s1, s2, ..., sn)字符串拼接,将 s1, s2, ..., sn 拼接成一个字符串
LOWER(str)将字符串全部转为小写
UPPER(str)将字符串全部转为大写
LPAD(str, n, pad)左填充,用字符串 padstr 的左边进行填充,达到 n 个字符串长度
RPAD(str, n, pad)右填充,用字符串 padstr 的右边进行填充,达到 n 个字符串长度
TRIM(str)去掉字符串头部和尾部的空格
SUBSTRING(str, start, len)返回从字符串 strstart 位置起的 len 个长度的字符串
REPLACE(s,s1,s2)使用字符串 s2 代替 s 中所有的 s1
LEFT(s,n)返回字符串 s 最左边 n 个字符
RIGHT(s,n)返回字符串 s 最右边 n 个字符

示例:

-- 拼接
SELECT CONCAT('Hello',' ','World');-- 返回'Hello World'
SELECT CONCAT('Hello',null,'World');-- 返回null
-- concat函数返回连接参数s1、s2等产生的字符串
-- 任一参数为null时,则返回null

-- 查询首都和名称,其中首都需是国家名称的扩展,例如:答案中应该包括墨西哥城(Mexico City),因为它比墨西哥(Mexico)更长,而不应该将卢森堡(Luxembourg)包括在内,因为首都名与国家名相同
select capital, name
from world
where capital like cancat('%',name,'%') and capital != name;

-- 左右返回
select left('abcdefg',3)-- 返回'abc'
select right('abcdefg',3)-- 返回'efg'
select substring('abcdefg',2,3)-- 返回'bcd'
select substring('abcdefg',-2,3)-- 返回'bfg'
select substring('abcdefg',2)-- 返回'bcdefg'
-- substring函数返回字符串s从第n个字符起取长度为len的子字符串
-- n也可以作为负值,则从倒数第n个字符起取长度为len的子字符
-- 没有len值则取从第n个字符起到最后一位

-- 替换
select replace('MYSQLMYSQL','SQL','sql')-- 返回'MYsqlMYsql'
-- 小写
SELECT LOWER('Hello');-- 返回'hello'
-- 大写
SELECT UPPER('Hello');-- 返回'HELLO'
-- 左填充
SELECT LPAD('01', 5, '-');-- 返回'---01'
-- 右填充
SELECT RPAD('01', 5, '-');-- 返回'01---'
-- 去除前后空格(不去除中间空格)
SELECT TRIM(' Hello World ');-- 返回'Hello World'
-- 切片(起始索引为1)
SELECT SUBSTRING('Hello World', 1, 5);-- 返回'Hello'

2.数值函数

常见函数:

函数功能
CEIL(x)向上取整
FLOOR(x)向下取整
MOD(x, y)返回 x/y 的模
RAND()返回 0~1 内的随机数
ROUND(x, y)求参数 x 的四舍五入值,保留 y 位小数

示例:

round(3.15,1)
-- 返回3.2
round(14.15,-1)
-- 返回10
-- round函数对x值进行四舍五入,精确到小数点后y位
-- y为负值时,保留小数点左边相应的位数为0,不进行四舍五入

3.数据类型转换函数

函数功能
cast(value AS datatype)AS 关键字用于分隔两个参数,在 AS 之前的是要转换的值,在 AS 之后的是要转换的数据类型

常用 datatype:

datatype描述
datevalue 转换成 YYYY-MM-DD 格式
datetimevalue 转换成 YYYY-MM-DD HH:MM:SS 格式
timevalue 转换成 HH:MM:SS格式
charvalue 转换成 CHAR (固定长度的字符串)格式
signedvalue 转换成 INT (有符号的整数)格式
unsignedvalue 转换成 INT (无符号的整数)格式
decimalvalue 转换成 FLOAT (浮点数)格式
binaryvalue 转换成二进制格式

示例:

SELECT CAST('123' AS INT);
-- 结果:123(字符串 '123' 被转换为整数 123)

SELECT CAST('2023-10-15' AS DATE);
-- 结果:2023-10-15(字符串 '2023-10-15' 被转换为日期类型)

SELECT CAST(NULL AS VARCHAR);
-- 结果:NULL(NULL 可以被转换为任何类型,结果仍然是 NULL)

SELECT CAST('{"name": "Alice", "age": 30}' AS JSON);
-- 结果:JSON 对象 {"name": "Alice", "age": 30}

SELECT CAST(1 AS BOOLEAN);
-- 结果:TRUE(1 被转换为 TRUE,0 被转换为 FALSE)

注意事项:

  • 数据类型兼容性:转换时需确保源数据与目标数据类型兼容,否则会报错。例如,CAST('ABC' AS INT) 会失败,因为 'ABC' 无法转换为整数;
  • 数据库差异:不同数据库对数据类型的支持可能略有不同。例如:
    • MySQL 使用 VARCHAR,而 PostgreSQL 使用 TEXTVARCHAR
    • SQL Server 使用 NVARCHARVARCHAR
  • 性能影响:频繁使用 CAST 可能会影响查询性能,尤其是在大数据集上。

4.日期函数

常用函数:

函数功能
CURDATE()返回当前日期
CURTIME()返回当前时间
NOW()返回当前日期和时间
YEAR(date)获取指定 date 的年份
MONTH(date)获取指定 date 的月份
DAY(date)获取指定 date 的日期
DATE_ADD(date, INTERVAL expr type)返回一个日期/时间值加上一个时间间隔 expr 后的时间值
DATE_SUB(date, INTERVAL expr type)返回一个日期/时间值减去一个时间间隔 expr 后的时间值
DATEDIFF(date1, date2)返回起始时间 date1 和结束时间 date2 之间的天数
DATE_FORMAT(date,format)根据 format 指定的格式显示 date

示例:

-- 现在是 2024-06-19 02:00:19
select curdate()-- 返回'2024-06-19'
select curtime()-- 返回'02:00:19'
select now()-- 返回'2024-06-19 02:00:19'

-- 年月日
select year('2021-08-03')-- 返回'2021'
select month('2021-08-03')-- 返回'8'
select day('2021-08-03')-- 返回'3'

-- date_add
SELECT DATE_ADD(NOW(), INTERVAL 70 YEAR);
select date_add('2024-06-19 02:00:19',interval 1 second)-- 返回'2024-06-19 02:00:20'

-- date_sub
select date_sub('2024-06-19 02:00:19',interval 2 month)-- 返回'2024-04-19 02:00:19'

-- datediff
select datediff('2021-06-08','2021-06-01')-- 返回'7'
select datediff('2021-06-08 23:59:59','2021-06-01 21:00:00')-- 返回'7'
select datediff('2021-06-01','2021-06-08')-- 返回'-7'
-- datediff函数由date1-date2计算出间隔的时间,只有date的日期部分参与计算,时间不参与

日期格式字符串:

format含义
%a三个字符缩写的工作日名称,例如:Mon, Tue, Wed
%b三个字符缩写的月份名称,例如:Jan,Feb,Mar
%c以数字表示的月份值,例如:1, 2, 3…12
%D英文后缀如:0th, 1st, 2nd 等的一个月之中的第几天
%d如果是 1 个数字(小于 10 ),那么一个月之中的第几天表示为前导加 0, 如:00, 01,02, …31
%e没有前导零的月份的日子,例如:1,2,… 31
%f微秒,范围在 000000 … 999999
%H24 小时格式的小时,前导加 0,例如:00,01 … 23
%h小时,12 小时格式,带前导 0,例如:01,02 … 12
%I%h 相同
%i表示分,前导为 0,例如:00,01,… 59
%j一年中的的第几天,前导为 0,例如,001,002,… 366
%k24 小时格式的小时,无前导 0,例如:0,1,2 … 23
%l12 小时格式的小时,无前导 0,例如:0,1,2 … 12
%M月份全名称,例如:January, February,…December
%m具有前导 0 的月份名称,例如:00,01,02,… 12
%pAMPM,取决于其他时间说明符
%r表示时间,12 小时格式 hh:mm:ss AMhh:mm:ss PM
%S表示秒,前导为 0,如:00,01,… 59
%s%S 相同
%T表示时间,24小时格式 hh:mm:ss
%U周从星期日开始,一年的第一周是第一个包含星期日的周(即使该周只有一天),例如:00,01,02 … 53 时,前导为 0 的周数
%u周从星期一开始,一年的第一周是第一个包含星期一的周(即使该周只有一天),例如:00,01,02 … 53 时,前导为 0 的周数
%V%U 相同,它与 %X 一起使用
%v%u 相同,它与 %x 一起使用
%W工作日的全称,例如:Sunday, Monday,…, Saturday
%w工作日,以数字来表示(0 = 星期日,1 = 星期一等)
%X当前年份的四位数(如 2025),经常与 %V 一起使用
%x当前年份的四位数(如 2025),经常与 %v 一起使用
%Y表示年份,四位数,例如 2000,2001,… 等。
%y表示年份,两位数,例如 00,01,… 等。
%%将百分比( % )字符添加到输出

常用的日期格式字符串:

DATE_FORMAT字符串格式化日期
%Y-%m-%d2017/4/30
%e/%c/%Y4/7/2013
%c/%e/%Y7/4/2013
%d/%m/%Y4/7/2013
%m/%d/%Y7/4/2013
%e/%c/%Y %H:%i4/7/2013 11:20
%c/%e/%Y %H:%i7/4/2013 11:20
%d/%m/%Y %H:%i4/7/2013 11:20
%m/%d/%Y %H:%i7/4/2013 11:20
%e/%c/%Y %T4/7/2013 11:20
%c/%e/%Y %T7/4/2013 11:20
%d/%m/%Y %T4/7/2013 11:20
%m/%d/%Y %T7/4/2013 11:20
%a %D %b %YThu 4th Jul 2013
%a %D %b %Y %H:%iThu 4th Jul 2013 11:20
%a %D %b %Y %TThu 4th Jul 2013 11:20:05
%a %b %e %YThu Jul 4 2013
%a %b %e %Y %H:%iThu Jul 4 2013 11:20
%a %b %e %Y %TThu Jul 4 2013 11:20:05
%W %D %M %YThursday 4th July 2013
%W %D %M %Y %H:%iThursday 4th July 2013 11:20
%W %D %M %Y %TThursday 4th July 2013 11:20:05
%l:%i %p %b %e, %Y7/4/2013 11:20
%M %e, %Y4-Jul-13
%a, %d %b %Y %TThu, 04 Jul 2013 11:20:05

示例:

select date_format('2024-06-19 02:00:19','%a, %d %b %Y %T')
-- 返回'Wed, 19 Jun 2024 02:00:19'
select date_format('2024-06-19 02:00:19','%W %D %M %Y %H:%i')
-- 返回'Wednesday 19th June 2024 02:00'

5.流程函数

常用函数:

函数功能
IF(value, t, f)如果 valuetrue ,则返回 t ,否则返回 f
IFNULL(value1, value2)如果 value1 不为空,返回 value1 ,否则返回 value2
CASE WHEN [ val1 ] THEN [ res1 ] ... ELSE [ default ] END如果 val1true,返回 res1 ,… 否则返回 default 默认值
CASE [ expr ] WHEN [ val1 ] THEN [ res1 ] ... ELSE [ default ] END如果 expr 的值等于 val1 ,返回 res1 ,… 否则返回 default 默认值

示例:

-- 查询emp表的员工姓名和工作地址(北京|上海 → 一线城市,其他 → 二线城市)
select
	name,
	(case workaddress when '北京市' then '一线城市' when '上海市' then '一线城市' else '二线城市' end) as '工作地址'
from employee;

6.窗口函数

窗口函数功能:

  • ①同时具有分组和排序的功能;
  • ②不减少原表的行数。

基本语法:
<窗口函数> over ( [partition by <用于分组的列名>] [order by <用于排序的列名>] )
语法中 <窗口函数> 的位置,可以放以下两种函数:

  • 聚合函数,如sum, avg, count, max, min等。
  • 专用窗口函数,包括后面要讲到的rank, dense_rank, row_number等专用窗口函数;

函数:

  • 排名函数:根据 SQL 标准能够支持 4 种窗口函数用于排名计算。
    • ROW_NUMBER:根据指定的顺序,从1开始计算连续的行号;
    • NTILE:函数对一个数据分区中的有序结果集进行划分,将其分成数量大致相等的块,根据输入的块数和指定的窗口进行排序;
    • RANKDENSE_RANK:计算一组数值中的排序值。
  • 分布函数:分布函数主要作用是为静态统计服务提供数据的分布情况。
    • 排名分布函数:PERCENT_RANK (百分位排名)和 CUME_DIST (累积分布);
    • 逆分布函数:PERCENT_CONT (百分位连续)和 PERCENTILE_DISC (百分位离散)。
  • 偏移量函数LAGLEAD
    • LAG(col,n,DEFAULT):用于统计窗口内往上第 n 行值;
    • LEAD(col,n,DEFAULT):与 LAG 相反,用于统计窗口内往下第 n 行值。
  • 取值函数
    • FIRST_VALUE():取分组内排序后,截止到当前行,第一个值;
    • LAST_VALUE():取分组内排序后,截止到当前行,最后一个值。

万能模板:
select * from(select* rows number () over(partition by 分组 order by 排序 desc)as ranking from 表名) as a where ranking <=N;

注意事项:

  • partition by 不会改变原表的行数;group by 会改变原表的行数;
  • ②专用窗口函数里的 () 不需要任何参数,保持空着就行,反之聚合函数 () 不能为空;
  • ③因为窗口函数是对 where 或者 group by 子句处理后的结果进行操作,所以窗口函数原则上只能写在 select 子句中;
  • partition 子句可以省略,省略就是不指定分组,可以在每一行的数据里直观的看到,截止到本行数据,统计数据是多少(最大值、最小值等)。同时可以看出每一行数据,对整体统计数据的影响;
  • order by 子句也可以省略;
  • ⑥传统的聚合、排序等函数都是基于全局整表的,窗口函数可以基于表中的每个细分部分。

示例:

-- 查询每一年S14000021选区中所有候选人所在的团体(party)和得票数(votes),并对每一年中的所有候选人根据选票数的高低赋予名次,选票数最高则为1,第二名则为2,后续以此类推,最后根据团体(party)和年份(yr)排序
select yr, party, votes,
rank()over(partition by yr order by votes desc) as posn
from ge
where constituency = 'S14000021'
order by party, yr
-- ①where constituency='S14000021'从原表筛选出的数据
-- ②partition by yr依据yr对数据分区
-- ③order by votes desc“在依据yr的分区内,对votes降序排序”,通过rank()指定排序方法
-- ④order by party,yr依次依据party和yr对全表进行排序select选取显示字段
-- 1.窗口函数只能写在select字句中
-- 2.窗口函数中的partition by子句可以指定数据的分区,和group by要去重分组不同的是,partitionby只分区不去重
-- 3.窗口函数中没有partition by子句时,即不对数据分区,直接整个表为一个区
-- 4.排序窗口函数中order by子句是必选顶,窗口函数中order by子句在分区内,依据指定字段和排序方法对数据行排序
-- 5.rank()、dense_rank()、row_number()指定排序赋值方法,对比三个排序窗口函数的异同

select name, date_format(whn,'%Y-%m-%d') date,
confirmed as 当天截至时间累计确诊人数, lag(confirmed,1)over(partition by name order by whn) as 昨天截至时间累计确诊人数,
(confirmed -lag(confirmed,1)over(partition by name order by whn))每天新增确诊人数
from covid
where name in ('France','Germany') and month(whn) = 1
order by whn
-- ①partition by name对筛选后的数据依据name分区
-- ②order by whn在分区内依据whn排序
-- ③lag(confirmed,1)指定偏移字段confirmed,偏移量为1,该列数据就会在confirmed列每行向上取1行,confirmed -lag(confirmed,1)原字段减去偏移后的字段得到新增人数
-- ④order by whn对全表依据whn升序排序
-- ⑤在排序后提取要显示的字段
-- 1.偏移分析窗口函数中order by子句是必选顶
-- 2.lag()和lead()指定偏移的方向,lag是向上偏移,行向上取数据;lead是向下偏移,行向下取数据
-- 3.lag(字段名,偏移量[,默认值])over()还有一个参数为默认值,是可选项,在分区中没有前一行的情况下填充默认值,不填的情况下默认是null

参考资料

[1] 黑马程序员 MySQL数据库入门到精通
[2] 数据库窗口函数总结_数据库 每个数据的窗口计算-CSDN博客

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值