摘要:本文介紹數據庫中的函數與約束,函數含字符串、數值、日期、流程四類,可實現字符串處理、數值計算等需求。約束分六類,重點講外鍵約束的語法、刪除更新行為,保證數據正確完整。
思維導圖
1. 函數
函數是指一段可以直接被另一段程序調用的程序或代碼。這意味著,在 MySQL 中已經為我們提供了這一段程序或代碼,我們只需在合適的業務場景調用對應的函數,即可完成對應的業務需求。
MySQL 中的函數主要分為四類:字符串函數、數值函數、日期函數、流程函數? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
1.1 字符串函數
MySQL 中內置了諸多字符串函數,常用的幾個如下:
函數 | 功能 |
---|---|
CONCAT(S1,S2,...Sn) | 字符串拼接,將 S1、S2、...、Sn 拼接成一個字符串 |
LOWER(str) | 將字符串 str 全部轉為小寫 |
UPPER(str) | 將字符串 str 全部轉為大寫 |
LPAD(str,n,pad) | 左填充,用字符串 pad 對 str 的左邊進行填充,使總長度達到 n 個字符 |
RPAD(str,n,pad) | 右填充,用字符串 pad 對 str 的右邊進行填充,使總長度達到 n 個字符 |
TRIM(str) | 去掉字符串頭部和尾部的空格 |
SUBSTRING(str,start,len) | 返回從字符串 str 的 start 位置起,長度為 len 的子字符串 |
使用方法:select? 函數
演示如下:
A. concat:字符串拼接? ???
select concat('Hello' , ' MySQL');
B. lower:全部轉小寫
select lower('Hello');
C. upper:全部轉大寫
select upper('Hello');
D. lpad:左填充
select lpad('01', 5, '-');
E. rpad:右填充
select rpad('01', 5, '-');
F. trim:去除空格
select trim(' Hello MySQL ');
G. substring:截取子字符串??
select substring('Hello MySQL',1,5);
案例
由于業務需求變更,企業員工的工號統一改為 5 位數,目前不足 5 位數的需在前面補 0(例如:1 號員工的工號應改為 00001)。
update emp set workno = lpad(workno, 5, '0');
處理完畢后,具體的數據如下:
id | workno | name | gender | age | idcard | workaddress | entrydate |
---|---|---|---|---|---|---|---|
1 | 00001 | 抖音號:1332402852 | 女 | 20 | 123456789012345678 | 北京 | 2000-01-01 |
2 | 00002 | 張無忌 | 男 | 18 | 123456789012345670 | 北京 | 2005-09-01 |
3 | 00003 | 韋一笑 | 男 | 38 | 123456789712345670 | 上海 | 2005-08-01 |
4 | 00004 | 趙敏 | 女 | 18 | 123456757123845670 | 北京 | 2009-12-01 |
5 | 00005 | 小昭 | 女 | 16 | 123456769012345678 | 上海 | 2007-07-01 |
6 | 00006 | 楊逍 | 男 | 28 | 12345678931234567X | 北京 | 2006-01-01 |
7 | 00007 | 抖音號:1232402856 | 男 | 40 | 123456789212345678 | 北京 | 2005-05-01 |
8 | 00008 | 黛綺絲 | 女 | 38 | 123456157123645670 | 天津 | 2015-05-01 |
9 | 00009 | 范涼涼 | 女 | 45 | 123156789012345678 | 北京 | 2010-04-01 |
10 | 00010 | 陳友諒 | 男 | 53 | 123456789012345670 | 上海 | 2011-01-01 |
11 | 00011 | 張士誠 | 男 | 55 | 123567897123465670 | 江蘇 | 2015-05-01 |
12 | 00012 | 常遇奇 | 男 | 32 | 123446757152345678 | 北京 | 2004-02-01 |
13 | 00013 | 張三豐 | 男 | 88 | 123656789012345678 | 江蘇 | 2020-11-01 |
14 | 00014 | 滅絕 | 女 | 65 | 123456719012345670 | 西安 | 2019-05-01 |
15 | 00015 | 胡青牛 | 男 | 70 | 12345674971234567X | 西安 | 2018-04-01 |
16 | 00016 | 周芷若 | 女 | 18 | null | 北京 | 2012-06-01 |
1.2 數值函數
常見的數值函數如下:
函數 | 功能 |
---|---|
CEIL(x) | 向上取整 |
FLOOR(x) | 向下取整 |
MOD(x,y) | 返回 x 除以 y 的余數(模) |
RAND() ? | 返回 0~1 范圍內的隨機數 |
ROUND(x,y) ? | 對參數 x 進行四舍五入,保留 y 位小數 |
演示如下:
A. ceil:向上取整
select ceil(1.1);
B. floor:向下取整
select floor(1.9);
C. mod:取模
select mod(7,4);
D. rand:獲取隨機數
select rand();
E. round:四舍五入
select round(2.344,2);
案例?????
通過數據庫的函數,生成一個六位數的隨機驗證碼。
思路:通過 rand()
函數可獲取 0~1 之間的隨機數,將其乘以 1000000 后,舍棄小數部分,若結果長度不足 6 位,則在前面補 0。
select lpad(round(rand()*1000000 , 0), 6, '0');
1.3 日期函數
常見的日期函數如下:
函數 | 功能 |
---|---|
CURDATE() | 返回當前日期(格式:YYYY-MM-DD) |
CURTIME() | 返回當前時間(格式:HH:MM:SS) |
NOW() | 返回當前日期和時間(格式:YYYY-MM-DD HH:MM:SS) |
YEAR(date) | 獲取指定 date 的年份 |
MONTH(date) | 獲取指定 date 的月份 |
DAY(date) | 獲取指定 date 的日期 |
DATE_ADD(date, INTERVAL expr type) | 返回一個日期 / 時間值,為指定 date 加上一個時間間隔 expr 后的結果 |
DATEDIFF(date1,date2) | 返回起始時間 date1 和結束時間 date2 之間的天數(date1 - date2) |
演示如下:
A. curdate:當前日期
select curdate();
B. curtime:當前時間
select curtime();
C. now:當前日期和時間
select now();
D. YEAR、MONTH、DAY:獲取當前年、月、日
select YEAR(now());select MONTH(now());select DAY(now());
E. date_add:增加指定的時間間隔
select date_add(now(), INTERVAL 70 YEAR );
F. datediff:獲取兩個日期相差的天數
select datediff('2021-10-01', '2021-12-01');
案例
查詢所有員工的入職天數,并根據入職天數倒序排序。
思路:入職天數 = 當前日期 - 入職日期,可通過 datediff
函數實現。
select name, datediff(curdate(), entrydate) as 'entrydays' from emp order by entrydays desc;
1.4 流程函數
流程函數是一類常用函數,可在 SQL 語句中實現條件篩選,從而提升語句效率。
函數 | 功能 |
---|---|
IF(value, t, f) | 若 value 為 true,則返回 t;否則返回 f |
IFNULL(value1, value2) | 若 value1 不為空,則返回 value1;否則返回 value2 |
CASE WHEN [val1] THEN [res1] ... ELSE [default] END | 若 val1 為 true,則返回 res1;... 若所有條件都不滿足,則返回 default 默認值 |
CASE [expr] WHEN [val1] THEN [res1] ... ELSE [default] END | 若 expr 的值等于 val1,則返回 res1;... 若所有條件都不滿足,則返回 default 默認值 |
演示如下:
A. if
select if(false, 'Ok', 'Error');
B. ifnull
select ifnull('Ok','Default');select ifnull('','Default');select ifnull(null,'Default');
C. case when then else end
需求:查詢 emp 表的員工姓名和工作地址(北京 / 上海 → 一線城市,其他 → 二線城市)
select
name,
( case workaddress when '北京' then '一線城市' when '上海' then '一線城市' else '二線城市' end ) as '工作地址'
from emp;
案例
先創建并插入數據到學員成績表 score
:
create table score(id int comment 'ID',name varchar(20) comment '姓名',math int comment '數學',english int comment '英語',chinese int comment '語文') comment '學員成績表';insert into score(id, name, math, english, chinese) VALUES (1, 'Tom', 67, 88, 95), (2, 'Rose' , 23, 66, 90),(3, 'Jack', 56, 98, 76);
查詢學員成績,并顯示各科成績等級(≥85 為優秀,≥60 為及格,否則為不及格):
select id,name,(case when math >= 85 then '優秀' when math >=60 then '及格' else '不及格' end ) '數學',(case when english >= 85 then '優秀' when english >=60 then '及格' else '不及格' end ) '英語',(case when chinese >= 85 then '優秀' when chinese >=60 then '及格' else '不及格' end ) '語文'from score;
函數場景回顧
數據庫中存儲入職日期(如 2000-01-01),如何快速計算出入職天數?
答案:
datediff
函數。數據庫中存儲學生分數值(如 98、75),如何快速判定分數等級?
答案:
case ... when ...
流程函數。
2. 約束
2.1 概述
概念:約束是作用于表中字段上的規則,用于限制存儲在表中的數據。
目的:保證數據庫中數據的正確、有效性和完整性。
分類:
約束 | 描述 | 關鍵字 |
---|---|---|
非空約束 | 限制該字段的數據不能為 null | NOT NULL |
唯一約束 | 保證該字段的所有數據都是唯一、不重復的 | UNIQUE |
主鍵約束? | 主鍵是一行數據的唯一標識,要求非空且唯一 | PRIMARY KEY |
默認約束 | 保存數據時,如果未指定該字段的值,則采用默認值 | DEFAULT |
檢查約束 | 保證字段值滿足某一個條件 | CHECK |
外鍵約束? | 用來讓兩張表的數據之間建立連接,保證數據的一致性和完整性 | FOREIGN KEY |
注意:約束是作用于表中字段上的,可以在創建表 / 修改表的時候添加約束。
2.2 外鍵約束
2.2.1 介紹
外鍵:用來讓兩張表的數據之間建立連接,從而保證數據的一致性和完整性。
2.2.2 語法
1). 添加外鍵
-- 方式1:創建表時添加
?
CREATE TABLE 表名(
?
字段名 數據類型,
?
[CONSTRAINT] [外鍵名稱] FOREIGN KEY (外鍵字段名) REFERENCES 主表 (主表列名)
?
);
?
-- 方式2:修改表時添加
?
ALTER TABLE 表名 ADD CONSTRAINT [外鍵名稱] FOREIGN KEY (外鍵字段名) REFERENCES 主表 (主表列名);
???????? ? ?多了一個藍色小鑰匙?
2). 刪除外鍵
ALTER TABLE 表名 DROP FOREIGN KEY 外鍵名稱;
案例:刪除 emp 表的外鍵 fk_emp_dept_id
alter table emp drop foreign key fk_emp_dept_id;
2.3.3 刪除 / 更新
添加外鍵后,刪除 / 更新父表數據時產生的約束行為,稱為刪除 / 更新行為,具體如下:
行為 | 說明 |
---|---|
NO ACTION | 當在父表中刪除 / 更新對應記錄時,先檢查該記錄是否有對應外鍵,若有則不允許刪除 / 更新(與 RESTRICT 一致),默認行為 |
RESTRICT | 當在父表中刪除 / 更新對應記錄時,先檢查該記錄是否有對應外鍵,若有則不允許刪除 / 更新(與 NO ACTION 一致),默認行為 |
CASCADE | 當在父表中刪除 / 更新對應記錄時,先檢查該記錄是否有對應外鍵,若有則同步刪除 / 更新子表中關聯的外鍵記錄 |
SET NULL | 當在父表中刪除對應記錄時,先檢查該記錄是否有對應外鍵,若有則將子表中該外鍵值設為 null(需外鍵允許取 null) |
SET DEFAULT | 父表有變更時,子表將外鍵列設為默認值(Innodb 不支持) |
具體語法
ALTER TABLE 表名 ADD CONSTRAINT 外鍵名稱 FOREIGN KEY (外鍵字段) REFERENCES 主表名 (主表字段名) ON UPDATE CASCADE ON DELETE CASCADE;
演示
NO ACTION 是默認行為,已通過前面語法測試,此處演示 CASCADE 和 SET NULL 兩種行為:
1). CASCADE
alter table emp add constraint fk_emp_dept_id foreign key (dept_id) references dept(id) on update cascade on delete cascade ;
A. 修改父表數據:將 dept 表中 id 為 1 的記錄修改為 6。
結果:子表 emp 中 dept_id 值為 1 的記錄,同步變為 6,體現 CASCADE 級聯更新效果。B. 刪除父表數據:刪除 dept 表中 id 為 6 的記錄。
結果:父表數據刪除成功,子表中關聯的記錄也被級聯刪除,體現 CASCADE 級聯刪除效果。 注意:一般業務系統中,不會修改表的主鍵值。
2). SET NULL
先刪除已建立的外鍵 fk_emp_dept_id,再恢復 emp、dept 表數據。
執行以下語句添加外鍵并設置 SET NULL 行為
alter table emp add constraint fk_emp_dept_id foreign key (dept_id) references dept(id) on update set null on delete set null ;
大功告成!