本文中总结了SQL
中常用的内置函数,包含通用聚合函数、安全检测函数、数学统计函数、字符串函数等
语句 | 含义 | 示例 |
---|---|---|
arbitrary(x) |
随机返回x列中的一个值。 | latency > 100 | select arbitrary(method) |
avg(x) |
计算x列的算数平均值。 | latency > 100 | select avg(latency) |
checksum(x) |
计算某一列的checksum,返回base64编码。 | latency > 100 | select checksum(method) |
count(*) |
表示所有的行数。 | - |
count(x) |
计算某一列非null的个数。 | latency > 100 | select count(method) |
count(数字) |
count(数字) ,如count(1) ,等同于count(*) ,表示所有的行数。 |
- |
count_if(x) |
计算x=true的个数。 | latency > 100 | select count_if(url like ‘%abc’) |
geometric_mean(x) |
计算某一列的几何平均数。 | latency > 100 | select geometric_mean(latency) |
max_by(x,y) |
返回当y取最大值时,x当前的值。 | 查询延时最高的时候,对应的method:latency>100 | select max_by(method,latency) |
max_by(x,y,n) |
返回y最高的n行,对应的x的值。 | 查询延时最高的3行,对应的method:latency > 100 | select max_by(method,latency,3) |
min_by(x,y) |
返回当y取最小值时,x当前的值。 | 查询延时最低的请求,对应的method:* | select min_by(x,y) |
min_by(x,y,n) |
返回y最小的n行,对应的x的值。 | 查询延时最小的3行,对应的method: * | select min_by(method,latency,3) |
max(x) |
返回最大值。 | latency > 100| select max(inflow) |
min(x) |
返回最小值。 | latency > 100| select min(inflow) |
sum(x) |
返回x列的和。 | latency > 10 | select sum(inflow) |
bitwise_and_agg(x) |
对某一列的所有数值做and计算。 | - |
bitwise_or_agg(x) |
对某一列的数值做or计算。 | - |
函数名 | 含义 | 样例 |
---|---|---|
security_check_ip | 检查IP是否安全,其中:返回1:命中,表示不安全返回0:未命中 | select security_check_ip(real_client_ip) |
security_check_domain | 检查Domain是否安全,其中:返回1:命中,表示不安全返回0:未命中 | select security_check_domain(site) |
security_check_url | 检查URL是否安全,其中:返回1:命中,表示不安全返回0:未命中 | select security_check_domain(concat(host, url)) |
函数 | 含义 | 示例 |
---|---|---|
下标运算符[] | 获取map中某个Key对应的结果。 | 无 |
histogram(x) | 按照x的每个值进行GROUP BY并计算count。语法相当于select count group by x 。说明 返回结果为JSON格式。 |
latency > 10 | select histogram(status) ,等同于latency > 10 | select count(1) group by status 。 |
histogram_u(x) | 按照x的每个值进行GROUP BY并计算count。说明 返回结果为多行多列。 | latency > 10 | select histogram(status) ,等同于latency > 10 | select count(1) group by status 。 |
map_agg(Key,Value) | 返回Key、Value组成的map,并返回每个Key随机的Value。 | latency > 100 | select map_agg(method,latency) |
multimap_agg(Key,Value) | 返回Key、Value组成的多Value map,并返回每个Key的所有的Value。 | latency > 100 | select multimap_agg(method,latency) |
cardinality(x) → bigint | 获取map的大小。 | 无 |
element_at(map``, key) → V | 获取Key对应的Value。 | 无 |
map() → map`` | 返回一个空的map。 | 无 |
map(array, array ) → map`` |
将两个数组转换成Key、Value组成的Map。 | SELECT map(ARRAY[1,3], ARRAY[2,4]); — {1 -> 2, 3 -> 4} |
map_from_entries(array> ) → map`` |
把一个多维数组转化成map。 | SELECT map_from_entries(ARRAY[(1, ‘x’), (2, ‘y’)]); — {1 -> ‘x’, 2 -> ‘y’} |
map_concat(map1, map2 , …, mapN) → map |
求多个map的并集,如果某个Key存在于多个map中,则取最后一个。 | 无 |
map_filter(map, function) → map |
请参见Lambda函数中map_filter函数。 | 无 |
map_keys(x) → array |
获取map中所有的Key并以array的形式返回。 | 无 |
map_values(x) → array |
获取map中所有的Value并以array的形式返回。 | 无 |
桶是按照聚集程度均分的,每个结果里显示这个区域的均值和个数
函数 | 说明 | 示例 |
---|---|---|
approx_distinct(x) |
估算x列的唯一值的个数。 | - |
approx_percentile(x,percentage) |
对于x列排序,找出大约处于percentage位置的数值。 | 找出位于一半位置的数值:approx_percentile(x,0.5) 。 |
approx_percentile(x, percentages) |
与approx_percentile(x,percentage) 用法类似,但可以指定多个percentage,找出每个percentage对应的数值。 |
approx_percentile(x,array[0.1,0.2]) |
numeric_histogram(buckets, Value) |
对于数值列,分多个桶进行统计。即把Value一列,分到桶中,桶的个数为buckets。返回内容为每个桶的Key及对应的count数值,相当于针对数值的select count group by 。说明 返回结果的格式为JSON。 |
对于POST请求,把延时分为10个桶,查看每个桶的大小:method:POST | select numeric_histogram(10,latency) 。 |
numeric_histogram_u(buckets, Value) |
对于数值列,分多个桶进行统计。即把Value一列,分到桶中,桶的个数为buckets。返回内容为每个桶的Key及对应的count数值,相当于针对数值的select count group by 。说明 返回结果的格式为多行多列。 |
对于POST请求,把延时分为10个桶,查看每个桶的大小:method:POST | select numeric_histogram_u(10,latency) 。 |
语句 | 含义 | 示例 |
---|---|---|
corr(y, x) |
给出两列的相关度,结果从0到1。 | latency>100| select corr(latency,request_size) |
covar_pop(y, x) |
计算总体协方差。 | latency>100| select covar_pop(request_size,latency) |
covar_samp(y, x) |
计算样本协方差。 | latency>100| select covar_samp(request_size,latency) |
regr_intercept(y, x) |
返回输入值的线性回归截距。 y是依赖值, x是独立值。 | latency>100| select regr_intercept(request_size,latency) |
regr_slope(y,x) |
返回输入值的线性回归斜率。 y是依赖值, x是独立值。 | latency>100| select regr_slope(request_size,latency) |
stddev(x) 或stddev_samp(x) |
返回x列的样本标准差。 | latency>100| select stddev(latency) |
stddev_pop(x) |
返回x列的总体标准差。 | latency>100| select stddev_pop(latency) |
variance(x) 或 var_samp(x) |
计算x列的样本方差。 | latency>100| select variance(latency) |
var_pop(x) |
计算x列的总体方差。 | latency>100| select variance(latency) |
支持的运算符号:+、-、*、/、%
;可以用在select
句子中
函数名 | 含义 |
---|---|
abs(x) |
返回x列的绝对值。 |
cbrt(x) |
返回x列的立方根。 |
ceiling(x) |
返回x列向上最接近的整数。 |
cosine_similarity(x,y) |
返回稀疏向量x和y之间的余弦相似度。 |
degrees |
把弧度转化为度。 |
e() |
返回自然常数。 |
exp(x) |
返回自然常数的指数。 |
floor(x) |
返回x向下最接近的整数。 |
from_base(string,radix) |
以radix进制解释string。 |
ln(x) |
返回自然对数。 |
log2(x) |
返回以2为底,x的对数。 |
log10(x) |
返回以10为底,x的对数。 |
log(x,b) |
返回以b为底,x的对数。 |
pi() |
返回π。 |
pow(x,b) |
返回x的b次幂。 |
radians(x) |
把度转化成弧度。 |
rand() |
返回随机数。 |
random(0,n) |
返回[0,n)随机数。 |
round(x) |
x四舍五入。 |
round(x, y) |
对x保留y个小数为,例如round(1.012345,2) = 1.01。 |
sqrt(x) |
返回x的平方根。 |
to_base(x, radix) |
把x以radix进制表示。 |
truncate(x) |
丢弃掉x的小数部分。 |
acos(x) |
反余弦。 |
asin(x) |
反正弦。 |
atan(x) |
反正切。 |
atan2(y,x) |
y/x的反正切。 |
cos(x) |
余弦。 |
sin(x) |
正弦。 |
cosh(x) |
双曲余弦。 |
tan(x) |
正切。 |
tanh(x) |
双曲正切。 |
infinity() |
返回正无穷的数值。 |
is_infinity(x) |
判断值是否是无限值。 |
is_finity(x) |
判断是否是有限值。 |
is_nan(x) |
判断是否是非数值。 |
函数名 | 含义 |
---|---|
chr(x) |
把int类型转化成对应的ASCII码,例如chr(65) 结果为A 。 |
codepoint (x) |
把一个ASCII码转化成int类型的编码,例如codepoint('A') 结果为65 。 |
length(x) |
字段长度。 |
levenshtein_distance(string1, string2) |
返回两个字符串的最小编辑距离。 |
lower(string) |
转化成小写。 |
lpad(string, size, padstring) |
把string对齐到size大小,如果小于size,用padstring从左侧补齐到;如果大于size则截取到size个。 |
rpad(string, size, padstring) |
类似lpad ,从右侧补齐string。 |
ltrim(string) |
删掉左侧的空白字符。 |
replace(string, search) |
把字符串中string中的search删掉。 |
replace(string, search,rep) |
把字符串中string中的search替换为rep。 |
reverse(string) |
翻转string。 |
rtrim(string) |
删掉字符串结尾的空白字符。 |
split(string,delimeter,limit) |
把字符串分裂成array,最多取limit个值。生成的结果为数组,下标从1开始。 |
split_part(string,delimeter,offset) |
把字符串分裂成array,取第offset个字符串。生成的结果为字符串。 |
split_to_map(string, entryDelimiter, keyValueDelimiter) → map |
把string按照entryDelemiter分割成多个entry,每个entry再按照keyValueDelimiter划分成key value。最终返回一个map。 |
position(substring IN string) |
获取string中,substring最先开始的位置。 |
strpos(string, substring) |
查找字符串中的子串的开始位置。返回结果从1开始,如果不存在则返回0。 |
substr(string, start) |
返回字符串的子串,start下标从1开始。 |
substr(string, start, length) |
返回字符串的子串,start下标从1开始,length指定子串的长度。 |
trim(string) |
删掉字符串开头和结尾的空白字符。 |
upper(string) |
转化为大写字符。 |
concat(string,string......) |
把两个或多个字符串拼接成一个字符串。 |
hamming_distance (string1,string2) |
获得两个字符串的海明距离。 |
日期和时间函数主要是包含:
1512374067
表示的时间是Mon Dec 4 15:54:27 CST 2017
。日志服务每条日志中内置的时间__time__
即为这种类型。函数名 | 含义 | 样例 |
---|---|---|
current_date |
当天日期。 | latency>100| select current_date |
current_time |
当前时间。 | latency>100| select current_time |
current_timestamp |
结合current_date 和current_time的结果。 | latency>100| select current_timestamp |
current_timezone() |
返回时区。 | latency>100| select current_timezone() |
from_iso8601_timestamp(string) |
把iso8601时间转化成带时区的时间。 | latency>100| select from_iso8601_timestamp(iso8601) |
from_iso8601_date(string) |
把iso8601转化成天。 | latency>100| select from_iso8601_date(iso8601) |
from_unixtime(unixtime) |
把unix时间转化为时间戳。 | latency>100| select from_unixtime(1494985275) |
from_unixtime(unixtime,string) |
以string为时区,把unixtime转化成时间戳。 | latency>100| select from_unixtime (1494985275,'Asia/Shanghai') |
localtime |
本地时间。 | latency>100| select localtime |
localtimestamp |
本地时间戳。 | latency>100| select localtimestamp |
now() |
等同于current_timestamp 。 |
- |
to_unixtime(timestamp) |
timestamp转化成unixtime。 | *| select to_unixtime('2017-05-17 09:45:00.848 Asia/Shanghai') |
函数名 | 含义 | 样例 |
---|---|---|
date_format(timestamp, format) |
把timestamp转化成以format形式表示。 | latency>100 |
date_parse(string, format) |
把string以format格式解析,转化成timestamp。 | latency>100 |
格式 | 描述 |
---|---|
%a | 星期的缩写,即Sun、Sat等。 |
%b | 月份的缩写,即Jan、Dec等。 |
%c | 月份,数值类型,即1~12。 |
%D | 每月的第几天,带后缀,即0th、1st、2nd、3rd等。 |
%d | 每月第几天,十进制格式,范围为01~31。 |
%e | 每月第几天,十进制格式,范围为1~31。 |
%H | 小时,24小时制。 |
%h | 小时,12小时制。 |
%I | 小时,12小时制。 |
%i | 分钟,数值类型,范围为00~59。 |
%j | 每年的第几天,范围为001~366。 |
%k | 小时,范围为0~23。 |
%l | 小时,范围为1~12。 |
%M | 月份的英文表达,范围为January~December。 |
%m | 月份,数值格式,范围为01~12。 |
%p | AM或PM。 |
%r | 时间,12小时制,格式为hh:mm:ss AM/PM 。 |
%S | 秒,范围为00~59。 |
%s | 秒,范围为00~59。 |
%T | 时间,24时制,格式为 hh:mm:ss 。 |
%V | 每年的第几周,星期日是一周的第一天。范围为01~53,与%X同时使用。 |
%v | 每年的第几周,星期一是一周的第一天。范围为01~53,与%x同时使用。 |
%W | 星期几的名称,范围为Sunday到Saturday。 |
%w | 一周的第几天, 星期日为第0天。 |
%Y | 4 位数的年份。 |
%y | 2位数的年份。 |
%% | %转义字符。 |
按照秒、分钟、小时、日、月、年等进行对齐
date_trunc(unit,x)
*|select date_trunc('minute' , __time__) as t,
truncate (avg(latency) ) ,
current_date
group by t
order by t desc
limit 60
时间间隔函数用来执行时间段相关的运算,如在日期中添加或减去指定的时间间隔、计算两个日期之间的时间
函数名 | 含义 | 样例 |
---|---|---|
date_add(unit, value, timestamp) |
在timestamp 上加上value 个unit 。如果要执行减法,value 使用负值。 |
date_add('day', -7, '2018-08-09 00:00:00') 表示8月9号之前7天 |
date_diff(unit, timestamp1, timestamp2) |
表示timestamp1 和timestamp2 之间相差几个unit 。 |
date_diff('day', '2018-08-02 00:00:00', '2018-08-09 00:00:00') = 7 |
单位 | 说明 |
---|---|
millisecond | 毫秒 |
second | 秒 |
minute | 分钟 |
hour | 小时 |
day | 天 |
week | 周 |
month | 月 |
quarter | 季度,即三个月 |
year | 年 |
时序补全函数time_series
必须和group by time order by time
一起使用,且order by
不支持desc
排序方式
函数格式:
time_series(time_column, window, format, padding_data)
参数说明:
参数 | 说明 |
---|---|
time_column | 时间列,例如日志服务提供的默认时间字段__time__ 。格式为long类型或timestamp类型。 |
window | 窗口大小,由一个数字和单位组成。单位为s(秒)、m(分)、H (小时)、或d(天)。例如2h、5m、3d。 |
format | MySQL时间格式,表示最终输出的格式。 |
padding_data | 表示补全的内容,包括:0:补零。null:补null。last:补上一个值。next:补下一个值。avg:补前后的平均值。 |
URL函数支持从标准URL路径中提取字段,一个标准的URL如下:
[protocol:][//host[:port]][path][?query][#fragment]
函数名 | 含义 | 示例 | |
---|---|---|---|
输入样例 | 输出结果 | ||
url_extract_fragment(url) |
提取出URL中的fragment,结果为varchar类型。 | *| select url_extract_fragment('https://sls.console.aliyun.com/#/project/dashboard-demo/categoryList') |
输出结果为/project/dashboard-demo/categoryList 。 |
url_extract_host(url) |
提取出URL中的host,结果为varchar类型。 | *|select url_extract_host('http://www.aliyun.com/product/sls') 。 |
输出结果为www.aliyun.com 。 |
url_extract_parameter(url, name) |
提取出URL中的query中name对应的参数值,结果为varchar类型。 | *|select url_extract_parameter('http://www.aliyun.com/product/sls?userid=testuser','userid') |
输出结果为testuser 。 |
url_extract_path(url) |
提取出URL中的path,结果为varchar类型。 | *|select url_extract_path('http://www.aliyun.com/product/sls?userid=testuser') |
输出结果为/product/sls 。 |
url_extract_port(url) |
提取出URL中的端口,结果为bigint类型。 | *|select url_extract_port('http://www.aliyun.com:80/product/sls?userid=testuser') |
输出结果为80 。 |
url_extract_protocol(url) |
提取出URL中的协议,结果为varchar类型。 | *|select url_extract_protocol('http://www.aliyun.com:80/product/sls?userid=testuser') |
输出结果为http 。 |
url_extract_query(url) |
提取出URL中的query,结果为varchar类型。 | *|select url_extract_query('http://www.aliyun.com:80/product/sls?userid=testuser') |
输出结果为userid=testuser 。 |
url_encode(value) |
对url进行转义编码。 | *|select url_encode('http://www.aliyun.com:80/product/sls?userid=testuser') |
输出结果为http%3a%2f%2fwww.aliyun.com%3a80%2fproduct%2fsls%3fuserid%3dtestuser 。 |
url_decode(value) |
对url进行解码。 | *|select url_decode('http%3a%2f%2fwww.aliyun.com%3a80%2fproduct%2fsls%3fuserid%3dtestuser') |
输出结果为http://www.aliyun.com:80/product/sls?userid=testuser 。 |
函数名 | 含义 | 样例 |
---|---|---|
regexp_extract_all(string, pattern) |
返回字符串中命中正则式的所有子串,返回结果是一个字符串数组。 | *| SELECT regexp_extract_all('5a 67b 890m', '\d+') ,结果为['5','67','890'] ,*|SELECT regexp_extract_all('5a 67a 890m', '(\d+)a') 结果为['5a','67a'] 。 |
regexp_extract_all(string, pattern, group) |
返回字符串中命中正则式的第group个() 内部分,返回结果是一个字符串数组。 |
*| SELECT regexp_extract_all(‘5a 67a 890m’, ‘(\d+)a’,1) 结果为[‘5’,’67’] |
regexp_extract(string, pattern) |
返回字符串命中的正则式的第一个子串。 | *|SELECT regexp_extract('5a 67b 890m', '\d+') 结果为'5' |
regexp_extract(string, pattern,group) |
返回字符串命中的正则式的第group个() 内的第1个子串。 |
*|SELECT regexp_extract('5a 67b 890m', '(\d+)([a-z]+)',2) 结果为'a' |
regexp_like(string, pattern) |
判断字符串是否命中正则式,返回bool类型,正则式可以只命中字符串的一部分。 | *|SELECT regexp_like('5a 67b 890m', '\d+m') 结果为true |
regexp_replace(string, pattern, replacement) |
把字符串中命中正则式的部分替换成replacement。 | *|SELECT regexp_replace('5a 67b 890m', '\d+','a') 结果为'aa ab am' |
regexp_replace(string, pattern) |
把字符串中命中正则式的部分删除,相当于regexp_replace(string,patterm,'') 。 |
*|SELECT regexp_replace('5a 67b 890m', '\d+') 结果为'a b m' |
regexp_split(string, pattern) |
使用正则式把字符串切分成数组。 | *|SELECT regexp_split('5a 67b 890m', '\d+') 结果为['a','b','m'] |
JSON主要有两种结构:map和array。如果一个字符串解析成JSON失败,那么返回的是null。
函数名 | 含义 | 样例 |
---|---|---|
json_parse(string) |
把字符串转化成JSON类型。 | SELECT json_parse('[1, 2, 3]') 结果为JSON类型数组 |
json_format(json) |
把JSON类型转化成字符串。 | SELECT json_format(json_parse('[1, 2, 3]')) 结果为字符串 |
json_array_contains(json, value) |
判断一个JSON类型数值,或者一个字符串(内容是一个JSON数组)是否包含某个值。 | SELECT json_array_contains(json_parse('[1, 2, 3]'), 2)或 SELECT json_array_contains('[1, 2, 3]', 2) |
json_array_get(json_array, index) |
同json_array_contains ,是获取一个JSON数组的某个下标对应的元素。 |
SELECT json_array_get('["a", "b", "c"]', 0)结果为'a' |
json_array_length(json) |
返回JSON数组的大小。 | SELECT json_array_length('[1, 2, 3]') 返回结果3 |
json_extract(json, json_path) |
从一个JSON对象中提取值,JSON路径的语法类似$.store.book[0].title ,返回结果是一个JSON对象。 |
SELECT json_extract(json, '$.store.book'); |
json_extract_scalar(json, json_path) |
类似json_extract ,但是返回结果是字符串类型。 |
- |
json_size(json,json_path) |
获取JSON对象或数组的大小。 | SELECT json_size('[1, 2, 3]') 返回结果3 |
类型转换函数用于在查询中转换指定值或指定列的数据类型。
cast([key|value] as type)
参数 | 说明 |
---|---|
key | 日志的Key,表示将该字段所有的值都转换成指定类型 |
value | 常量值,表示将某个值转换成指定类型 |
将数字123转换为字符串(varchar)格式:
cast(123 AS varchar)
将uid字段转换为字符串(varchar)格式:
cast(uid AS varchar)
IP 地理函数可以识别一个 IP 是内网 IP还是外网 IP,也可以判断 IP 所属的国家、省份、城市
函数名 | 含义 | 样例 |
---|---|---|
ip_to_domain(ip) |
判断 IP 所在的域,是内网还是外网。返回 intranet 或 internet。 | SELECT ip_to_domain(ip) |
ip_to_country(ip) |
判断 IP 所在的国家。 | SELECT ip_to_country(ip) |
ip_to_province(ip) |
判断 IP 所在的省份。 | SELECT ip_to_province(ip) |
ip_to_city(ip) |
判断 IP 所在的城市。 | SELECT ip_to_city(ip) |
ip_to_geo(ip) |
判断 IP 所在的城市的经纬度,范围结果格式为纬度,经度 。 |
SELECT ip_to_geo(ip) |
ip_to_city_geo(ip) |
判断 IP 所在的城市的经纬度,返回的是城市经纬度,每个城市只有一个经纬度,范围结果格式为纬度,经度 。 |
SELECT ip_to_city_geo(ip) |
ip_to_provider(ip) |
获取 IP 对应的网络运营商。 | SELECT ip_to_provider(ip) |
ip_to_country(ip,'en') |
判断 IP 所在的国家,返回国家码。 | SELECT ip_to_country(ip,'en') |
ip_to_country_code(ip) |
判断 IP 所在的国家,返回国家码。 | SELECT ip_to_country_code(ip) |
ip_to_province(ip,'en') |
判断 IP 所在的省份,返回英文省名或者中文拼音。 | SELECT ip_to_province(ip,'en') |
ip_to_city(ip,'en') |
判断 IP 所在的城市,返回英文城市名或者中文拼音。 | SELECT ip_to_city(ip,'en') |
* | select count(1) as pv, ip_to_province(ip) as province -- 判断省份
where ip_to_domain(ip) != 'intranet' -- 过滤内网
group by province -- 分组
order by desc -- 降序
limit 10 -- 取出前10个
查看不同国家的平均响应延时、最大响应延时以及最大延时对应的 request
select avg(latency),
max(latency),
max_by(requestId, latency),
ip_to_country(ip) as country
group by country
limit 100
常用的地理函数包含:
函数名 | 含义 | 样例 |
---|---|---|
geohash(string) | 将纬度、经度用geohash编码,string为字符串类型,内容是纬度、逗号、经度。 | select geohash('34.1,120.6')= 'wwjcbrdnzs' |
geohash(lat,lon) | 将纬度、经度用geohash编码,参数分别是纬度和经度。 | select geohash(34.1,120.6)= 'wwjcbrdnzs' |
GROUP BY
支持多列。GROUP BY
支持通过SELECT
的列的别名来表示对应的KEY
select avg(latency), projectName, date_trunc('hour', __time__) as hour -- 取别名
group by ProjectName, hour
group by
支持grouping sets, cube, rollup
method:PostLogstoreLogs |select avg(latency) group by cube(projectName,logstore)
method:PostLogstoreLogs |select avg(latency) group by GROUPING SETS ( ( projectName,logstore), (projectName,method))
method:PostLogstoreLogs |select avg(latency) group by rollup(projectName,logstore)
在group by中提取非agg列:如果使用了group by语法,那么在select时,只能选择select group by 的列原始内容,或者对任意列进行聚合计算,不允许获取非group by列的内容
错误语法
*| select a,b, count(c),group by a -- b行由多个可供选择,系统不知道选择哪个
解决办法:使用arbitrary函数
*| select a, arbitrary(b), count(c) group by a
在日常工作中,经常会遇到需要在每组内排名,比如下面的业务需求:
排名问题:每个部门按业绩来排名
topN问题:找出每个部门排名前N的员工进行奖励
面对这类需求,就需要使用sql的高级功能窗口函数了。
窗口函数,也叫OLAP函数(online anallytical processing,联合分析处理)。窗口函数是用来跨行计算的。普通的SQL聚合函数是只能用来处理计算一行内的结果,窗口函数可以跨行计算,并且把结果填到每行中
基本语法
<窗口函数> over (partition by <用于分组的列名>
order by <用于排序的列名>)
<窗口函数>的位置可以放置两种函数:
因为窗口函数是对where或者group by子句处理后的结果进行操作,所以窗口函数原则上只能写在select子句中
使用demo
select key1,key2,value
rank() over (pratition by key2
order by value desc) as rnk
from orders
order by key1, rnk
函数 | 含义 |
---|---|
rank() | 在窗口内,按照某一列排序,返回在窗口内的序号。 |
row_number() | 返回在窗口内的行号。 |
first_value(x) | 返回窗口内的第一个value,一般用法是窗口内数值排序,获取最大值。 |
last_value(x) | 含义和first value相反。 |
nth_value(x, offset) | 窗口内的第offset个数。 |
lead(x,offset,defaut_value) | 窗口内x列某行之后offset行的值,如果不存在该行,则取default_value。 |
lag(x,offset,defaut_value) | 窗口内x列某行之前offset行的值,如果不存在该行,则取default_value。 |
如果想对每个班级内按照成绩排名:
得到如下结果
select *,
rank() over (partition by 班级 -- rank()是排序的函数;同时对表分组
order by 成绩 desc) as ranking -- 对分组后的结果进行降序
from 班级表
关键字:
select department, personId, sallary,
rank() over (Partition by department
order by sallary desc) as sallary_rank
order by department, sallary_rank
select department, personId, sallery * 1.0 / sum(sallery) over (partition by department) as sallary_percentage
having用于过滤group by之后的聚合计算结果,where是在聚合计算之前过滤原始数据
对输出结果进行排序
order by column [desc|asc]
实例demo
select avg(latency) as avg_latency, projectName
group by projectName
having avg(latency) > 570000
order by avg_latency desc;
用于限制输出结果的行数
limit N -- 取前N行数据
limit S, N -- 从S行开始,取出N行数据
limit
语法用于子查询内部offset
不能超过1,000,000,即S+N必须小于1,000,000只获取100行结果:
* | select distinct(url) from log limit 100
获取0行到第999行的结果,共计1000行:
* | select distinct(url) from log limit 0,1000
获取第1000行到第1999行的结果,共计1000行:
* | select distinct(url) from log limit 1000,1000
case when
语法对连续数据进行归类,例如从http_user_agent
中提取信息,归类成Android
和ios
两种
select case
when http_user_agent like '%android%' then 'andriod' -- case的两个判断语法
when http_user_agent like '%ios%' then 'ios'
else 'unknown' end -- else语句,end
as http_user_agent,
count(1) as pv
group by http_user_agent
计算不同延时区间的分布
select case
when latency < 10 then 's10'
when latency < 100 then 's100'
when latency < 1000 then 's1000'
when latency < 10000 then 's10000'
else 's_large' end
as latency_slot,
count(1) as pv
group by latency_slot
if
语法逻辑上等同于case when
语法
case
when condition then true_value
[ else false_value]
end
if(condition, true_value)
如果condition
是true
,返回true_value
,否则返回的是NULL
if(condition, true_value, false_value)
如果condition
是true
,返回true_value
,否则返回的是false_value
返回的是多个列的第一个非NULL值
coalesce(value1,value2,...)
如果value1
和value2
相等,返回的是NULL
;否则返回的是value1
nullif(value1,value2) -- 如果value1和value2相等,返回的是NULL;否则返回的是value1
二进制字符串类型varbinary
有别于字符串类型varchar
语句 | 说明 |
---|---|
连接函数 || | a || b 结果为ab 。 |
length(binary) → bigint | 返回二进制的长度。 |
concat(binary1, …, binaryN) → varbinary | 连接二进制字符串,等同于||。 |
to_base64(binary) → varchar | 把二进制字符串转换成base64。 |
from_base64(string) → varbinary | 把base64转换成二进制字符串。 |
to_base64url(binary) → varchar | 转化成url安全的base64。 |
from_base64url(string) → varbinary | 从url安全的base64转化成二进制字符串。 |
to_hex(binary) → varchar | 把二进制字符串转化成十六进制表示。 |
from_hex(string) → varbinary | 从十六进制转化成二进制。 |
to_big_endian_64(bigint) → varbinary | 把数字转化成大端表示的二进制。 |
from_big_endian_64(binary) → bigint | 把大端表示的二进制字符串转化成数字。 |
md5(binary) → varbinary | 计算二进制字符串的md5。 |
sha1(binary) → varbinary | 计算二进制字符串的sha1。 |
sha256(binary) → varbinary | 计算二进制字符串的sha256 hash。 |
sha512(binary) → varbinary | 计算二进制字符串的sha512。 |
xxhash64(binary) → varbinary | 计算二进制字符串的xxhash64。 |
语句 | 说明 | 示例 |
---|---|---|
bit_count(x, bits) → bigint | 统计x的二进制表示中,1的个数。 | SELECT bit_count(9, 64); — 2 SELECT bit_count(9, 8); — 2 SELECT bit_count(-7, 64); — 62 SELECT bit_count(-7, 8); — 6 |
bitwise_and(x, y) → bigint | 以二进制的形式求x,y的and的值。 | - |
bitwise_not(x) → bigint | 以二进制的形式求对x的所有位取反。 | - |
bitwise_or(x, y) → bigint | 以二进制形式对x,y求or。 | - |
bitwise_xor(x, y) → bigint | 以二进制形式对x,y求xor。 | - |
比和环比函数用于比较当前区间的计算结果和之前一个指定区间的结果
函数 | 含义 | 样例 |
---|---|---|
compare(value, time_window) |
表示将当前时段计算出来的value值和time_window计算出来的结果进行比较。value为double或long类型,time_window单位为秒;返回值为数组类型。返回值分别是当前值、time_window之前的值和当前值与之前值的比值。 | *|select compare( pv , 86400) from (select count(1) as pv from log) |
compare(value, time_window1, time_window2) |
表示当前区间分别和time_window1和time_window2之前的区间值进行比较,结果为json数组。其中,各个值的大小必须满足以下规则:[当前值,time_window1之前的值,time_window2之前的值,当前值/time_window1之前的值,当前值/time_window2之前的值]。 | * | select compare(pv, 86400, 172800) from ( select count(1) as pv from log) |
compare(value, time_window1, time_window2, time_window3) |
表示当前区间分别和time_window1和time_window2,time_window3之前的区间值进行比较,结果为json数组。其中,各个值的大小必须满足以下规则:[当前值,time_window1之前的值,time_window2之前的值,time_window3之前的值,当前值/time_window1之前的值,当前值/time_window2之前的值,当前值/time_window3之前的值]。 | * | select compare(pv, 86400, 172800,604800) from ( select count(1) as pv from log) |
ts_compare(value, time_window) |
表示当前区间分别和time_window1 和time_window2 之前的区间值进行比较,结果为json数组。其中,各个值的大小必须遵循以下规则:[当前值,time_window1之前的值,当前值/time_window1之前的值,前一个时间起点的unix时间戳]。用于时序函数比较,需要在SQL中对时间列进行GROUP BY。 |
例如,* | select t, ts_compare(pv, 86400 ) as d from(select date_trunc('minute',__time__ ) as t, count(1) as pv from log group by t order by t ) group by t 表示将当前时间段每分钟的计算结果和上一个时间段每分钟的计算结果进行比较。结果为:d:[1251.0,1264.0, 0.9897151898734177, 1539843780.0,1539757380.0]t:2018-10-19 14:23:00.000 。 |
计算当前1
小时和昨天同一个时间段的PV
比例
笔记:
PV(PageView)
页面点击量,每次刷新就算一次浏览,多次打开同一页面会累加
开始时间为2020-03-25 14:00:00;结束时间为2020-03-25 15:00:00。
select compare(pv, 86400) from (select count(1) as pv from log) -- 86400表示当前时间段减去86400秒
假设结果为:
[9.0,19.0,0.47368421052631579]
其中:
将数组展开成3列的写法为:
select diff[1], diff[2], diff[3]
from select(compare(pv, 86400) as diff
from (select count(1) as pv
from log))
比较运算判断参数的大小,可以适用于任何可比类型,例如:int、bigint、double、text
等
当用比较运算符比较两个值得时候,如果逻辑成立,则表示为True,否则返回False
运算符 | 含义 |
---|---|
< | 小于 |
> | 大于 |
<= | 小于或等于 |
>= | 大于或等于 |
= | 等于 |
<> | 不等于 |
!= | 不等于 |
between
用于判断一个参数的值是否在另外两个参数之间,范围为闭区间。
如果逻辑成立,则返回true;否则返回false。
示例:SELECT 3 BETWEEN 2 AND 6;
逻辑成立,返回true。
以上样例等同于SELECT 3 >= 2 AND 3 <= 6;
BETWEEN可以跟在not之后,用于相反逻辑的判断。
示例:SELECT 3 NOT BETWEEN 2 AND 6;
,逻辑不成立,返回false。
以上样例等同于SELECT 3 < 2 OR 3 > 6;
如果三个参数中任何一个包含Null,则返回的结果为Null。
用于判断参数是否为NULL
值
用于获取多列中的最大值或者最小值
select greatest(1,3,4) -- 返回的是4
比较判断用于判断参数是否满足条件
any
的用法相同三者必须紧跟在比较运算符之后
表达式 | 含义 |
---|---|
A = ALL (…) | A等于所有的值时,结果才是true。 |
A <> ALL (…) | A不等于所有的值时,结果才是true。 |
A < ALL (…) | A小于所有的值时,结果才是true。 |
A = ANY (…) | A等于任何一个值时,结果就为true,等同于 A IN (…)。 |
A <> ANY (…) | A不等于任何一个值时,结果为true。 |
A < ANY (…) | A小于其中最大值时,结果为true。 |
看几个例子
select 'hello' = any (values 'hello', 'world') -- true,只要满足一个
select 21 < all (values 19,20,21) -- false,需要全部满足
select 42 >= some(select 41 union all select 42 union all select 43); -- true
lambda匿名函数的基本形式为->
x -> x + 1
(x, y) -> x + y
x -> regexp_like(x, 'a+')
x -> x[1] / x[2]
x -> IF(x > 0, x, -x)
x -> COALESCE(x, 0)
x -> CAST(x AS JSON)
x -> x + TRY(1 / 0)
基本格式:filter(array
select filter (array [], x -> true); -- []
select filter (array [5, -6, null, 7], x -> x >0); --[5,7]
select filter (array [5,null,7,null], x -> x is not null); -- [5,7]
从map
中过滤数据,只获取满足function
且返回true
的元素对
基本语法格式:map_filter(map
SELECT map_filter(MAP(ARRAY[], ARRAY[]), (k, v) -> true); -- {}
SELECT map_filter(MAP(ARRAY[10, 20, 30], ARRAY['a', NULL, 'c']), (k, v) -> v IS NOT NULL); -- {10 -> a, 30 -> c}
SELECT map_filter(MAP(ARRAY['k1', 'k2', 'k3'], ARRAY[20, 3, 15]), (k, v) -> v > 10); -- {k1 -> 20, k3 -> 15}
基本语法格式为:reduce(array
, outputFunction) → R
详细步骤为
inputFunction(S,T)
,生成新状态Sselect reduce(array [], (s, x) -> s+x, s -> s); -- 0
select reduce(array [5,20,50], (s, x) -> s+x, s -> s); -- 75
select reduce(array [5,20,null,50], (s, x) -> s+x, s -> s); -- null,任何数加上NULL都是NULL
select reduce(array [5,20,null,50], (s, x) -> s + coalesce(x,0), s -> s); -- 75; coalesce返回的是多个列的第一个非NULL值
基本语法:transform(array
对数组中的每个元素,一次调用function
,生成新的结果U
select transform(array [], x -> x+1); --[]
select transform(array [5,6], x -> x+1); -- [6,7]
select transform(array [5,null,6], x -> coalesce(x,0) + 1); -- [6,1,7]
基本语法格式:zip_with(array
将两个array
合并,根据元素T、U
,通过函数生成新的array
中的元素R
SELECT zip_with(ARRAY[1, 3, 5], ARRAY['a', 'b', 'c'], (x, y) -> (y, x)); --调换前后两个数组的元素位置,生成新的数组:[['a', 1], ['b', 3],['c', 5]]
SELECT zip_with(ARRAY[1, 2], ARRAY[3, 4], (x, y) -> x + y); -- 对应位置上的元素相加,结果[4, 6]
SELECT zip_with(ARRAY['a', 'b', 'c'], ARRAY['d', 'e', 'f'], (x, y) -> concat(x, y)); -- 把前后两个数组的元素拼接,生成新的字符串:['ad', 'be', 'cf']
运算符 | 描述 | 样例 |
---|---|---|
AND | 只有左右运算数都是true时,结果才为true | a AND b |
OR | 左右运算数任一个为true,结果为true | a OR b |
NOT | 右侧运算数为false时,结果才为true | NOT a |
重点标记的一种情况
a | b | a AND b | a OR b |
---|---|---|---|
TRUE | TRUE | TRUE | TRUE |
TRUE | FALSE | FALSE | TRUE |
TRUE | NULL | NULL | TRUE |
FALSE | TRUE | FALSE | TRUE |
FALSE | FALSE | FALSE | FALSE |
FALSE | NULL | FALSE | NULL |
NULL | TRUE | NULL | TRUE |
NULL | FALSE | FALSE | NULL |
NULL | NULL | NULL | NULL |
SQL
中常用的4个join
用法
牢记此图!
牢记此图!
牢记此图!
以下面的两个表格为例子:
mysql> SELECT * FROM Table_A ORDER BY PK ASC;
+----+---------+
| PK | Value |
+----+---------+
| 1 | both ab |
| 2 | only a |
+----+---------+
2 rows in set (0.00 sec)
mysql> SELECT * from Table_B ORDER BY PK ASC;
+----+---------+
| PK | Value |
+----+---------+
| 1 | both ab |
| 3 | only b |
+----+---------+
2 rows in set (0.00 sec)
内连接,将左右两个表中能够关联的数据连接起来,并返回出结果;PK为公共字段
必须要有共同的字段!!!
SELECT A.PK AS A_PK, B.PK AS B_PK,
A.Value AS A_Value, B.Value AS B_Value
FROM Table_A A
INNER JOIN Table_B B
ON A.PK = B.PK;
左连接,返回左边表的全部记录,不管右表中有没有关联的数据。在右表中找到的关联数据列一并返回
select A.PK as A_PK,B.PK as B_PK, -- 字段取别名
A.Value as A_Value, B.Value as B_Value
From Table_A A -- 表取别名
left join Table_B B
on A.PK = B.PK;
右连接,返回右边表的全部记录,不管左表中有没有关联的数据。在左表中找到的关联数据列一并返回
select A.PK as A_PK,B.PK as B_PK, -- 字段取别名
A.Value as A_Value, B.Value as B_Value
From Table_A A -- 表取别名
right join Table_B B
on A.PK = B.PK;
常被称作外连接,全连接。外连接查询能返回左右表里的所有记录,其中左右表里能关联起来的记录被连接后返回。
mysql中目前没有full join功能
在复杂的业务场景下,日志数据的某一列可能会是较为复杂的格式,例如数组(array)、对象(map)、JSON等格式。对这种特殊格式的日志字段进行查询分析,可以使用unnest语法。
unnest接收的是array或者map类型
如果输入的是字符串类型,要先转成json类型,再转化成array类型或者map类型,转化格式:
cast(json_parse(array_column) as array(biginit))
语法 | 说明 |
---|---|
unnest( array) as table_alias(column_name) |
表示把array类型展开成多行,行的名称为column_name 。 |
unnest(map) as table(key_name, value_name) |
表示把map类型展开成多行,key的名称为key_name ,value的名称为value_name 。 |
select array_column, a from log, -- 展开每个元素
unnest(cast(json_parse(array_column) as array(bigint))) as t(a) -- 以t来命名新表,使用a来引用展开后的列
select sum(a) from log, -- 求和
unnest(cast(json_parse(array_column) as array(bigint))) as t(a)
select a, count(1) from log,
unnest(cast(json_parse(array_num) as array(bigint))) as t(a)
group by a
select map_column,a,b from log,
unnest(cast(json_parse(map_column) as map(varchar, bigint))) as t(a,b)
select key, sum(value) from log,
unnest(cast(json_parse(map_column) as map(varchar, bigint))) as t(key, value)
group by key;
histogram
函数类似于 count group by
语法,其结果通常是一连串的json数据
select key, value from (select histogram(method) as his from log),
unnest(his) as t(key,value)
numeric_histogram
语法是将数值列分配到多个桶中去,相当于是对数值列进行group by
select key,value from (select numeric_histogram(10, Latency) as his from log),
unnest(his) as t(key,value)
电话号码函数提供对中国内地区域电话号码的归属地查询功能
函数名 | 含义 | 样例 |
---|---|---|
mobile_province | 查看电话号码所属省份,需要传入电话的数字形式。字符串参数可以使用try_cast 进行转换。 |
* | select mobile_province(12345678)``* \| select mobile_province(try_cast('12345678' as bigint) ) |
mobile_city | 查看电话号码所属城市,需要传入电话的数字形式。字符串参数可以使用try_cast 进行转换。 |
* | select mobile_city(12345678)``* \| select mobile_city(try_cast('12345678' as bigint) ) |
mobile_carrier | 查看电话号码所属运营商,需要传入电话的数字形式。字符串参数可以使用try_cast 进行转换。 |
* | select mobile_carrier(12345678)``* \| select mobile_carrier(try_cast('12345678' as bigint) ) |
select mobile_city(try_cast("mobile" as bigint)) as "城市", -- try_cast将字符串转成数值型
mobile_province(try_cast("mobile" as bigint)) asd "省份",
count(1) as "请求次数"
group by "省份", "城市"
order by "请求次数" desc
limit 1000
)