🍖視圖、觸發器、事務、存儲過程、函數、流程控制

一.視圖

1.什麼是視圖

  • 視圖就是經過查詢獲得一張虛擬表(並不是真實存在), 而後保存下來, 下次能夠直接使用
  • 視圖的本質也是一張表

2.視圖的做用

  • 若是要頻繁的操做一張虛擬表, 就能夠將其製做成視圖後直接操做

3.視圖的使用

  • 語法 : create view [表名] as [查詢表的語句]html

  • 建立兩個相互關聯的表java

select * from emp;
select * from dep;

image-20210210131021920

  • 建立視圖
create view emp_dep_view as
    select * from
        emp inner join dep 
        on emp.dep_id=dep.did;
        
show tables;
select * from emp_dep_view;

image-20210210131555156

  • 修改視圖內容
update emp_dep_view set name="BigBob" where name="Bob";
select * from emp_dep_view;
select * from emp;

alter view emp_dep_view2 as select * from emp where id>4;
show tables;
select * from emp_dep_view2;

image-20210210131941975

咱們發現修改了視圖表, 原來的 emp 表的數據也發生了改變python

  • 刪除視圖
drop view emp_dep_view;
show tables;

image-20210210132210082

4.視圖總結

  • 修改視圖的內容會影響真正表的數據, 因此視圖通常不修改,只是用來查詢的
  • 視圖的修改通常只爭對建立視圖時as後面定義的虛擬表的sql查詢語句
  • 建立視圖在硬盤上只會有表結構(.frm), 沒有表數據(.idb). 數據仍是來自於以前的表(因此該視圖,原數據會改變)

致命的問題:視圖是存放到數據庫裏的,若是咱們程序中的sql過度依賴於數據庫中存放的視圖,那麼意味着,一旦sql須要修改且涉及到視圖的部分,則必須去數據庫中進行修改,而一般在公司中數據庫有專門的DBA負責,你要想完成修改,必須付出大量的溝通成本DBA可能纔會幫你完成修改,極其地不方便mysql

二.觸發器

1.什麼是觸發器

  • 對一張表進行 : 增、刪、改操做的時候, 自動觸發預先編譯好的 SQL 語句的執行 (沒有操做)

2.觸發器的做用

  • 保證數據的完整性, 還能夠起到相似於事務回滾的效果, 幫咱們實現監控、日誌等

3.自動觸發狀況

  • 增前、增後
  • 刪前、刪後
  • 改前、改後

4.注意點說明

  • delimiter : 改變輸入的結束符,默認狀況下輸入結束符是分號 ";",下面我把它改爲了自定義 "%%",這樣作的目的是把多條含分號的語句作個封裝,所有輸入完以後一塊兒執行,而不是一遇到默認的分號結束符就自動執行 (只在當前窗口有效)
  • new : 表示即將插入的數據行
  • old : 表示即將刪除的數據行

5.觸發器的使用

  • 完整語法
delimiter %%  # 修改結束符
create  trigger [觸發器名] [before/after] [insert/update/delete] on [表名]
for each row  # 表示每往上面建立的表進行指定操做以後就執行下面 "begin...end" 裏面的SQL語句
begin
    [sql 語句]
end %%
delimiter ;   # 將結束符改回來
  • 觸發器的命名(見明知意)
🥝建立一個往"t01"表內插入記錄以前觸發"sql"語句的觸發器
delimiter %%
create trigger tri_before_insert_t01 before insert on t01
for each row
begin
    [SQL語句]
end %%
delimiter ;

🥝建立一個在"t01"表刪除記錄以後觸發"sql"語句的觸發器
delimiter %%
create trigger tri_after_delete_t01 after delete on t01
for each row
begin
    [sql語句]
end %%
delimiter ;

🥝建立一個在對"t01"表修改數據以前就觸發"sql"語句的觸發器
delimiter %%
create trigger tri_before_update_t01 before update on t01
for each row
    [SQL語句]
end %%
delimiter ;

6.觸發器示例

  • 模擬 cmd 命令的執行, 執行失敗則添加到錯誤日誌中
🥝準備兩張表"cmd"、"error_log"
create table cmd(
    id int primary key auto_increment,
    user varchar(16) not null,
    permi char(4) not null,
    cmd varchar(60) not null,
    sub_time datetime,
    success enum("yes","no") not null default "no"
);

create table error_log(
    id int primary key auto_increment,
    error_cmd varchar(60),
    error_time datetime
);

🥝建立觸發器,當"cmd"表中的"cuccess"字段是"no",那麼將觸發執行"error_log"表的插入操做
delimiter %%
create trigger tri_after_insert_cmd after insert on cmd
for each row
begin
    if new.success="no" then  # 若是即將插入的記錄的"success"字段是"no",則執行下面的語句
        insert error_log(error_cmd,error_time) value(new.cmd,new.sub_time);  # 加分號
    end if;
end %%
delimiter ;

🥝開始模擬插入記錄
insert cmd(user,permi,cmd,sub_time,success) value
    ("shawn","0644","ls -l /root",now(),"yes"),
    ("shawn","0644","ps -elf",now(),"yes"),
    ("shawn","0644","groupadd xing",now(),"no"),
    ("shawn","0644","cat /etc/gshadow",now(),"no");
    
🥝查看"error_log"
select * from error_log;

image-20210212201410489

7.刪除觸發器

drop trigger tri_after_insert_cmd
  • 刪除以後,再向"cmd"表中插入記錄,字段"success"爲"no"數據所在的行就不會再添加到"error_log"中去了

image-20210212202349085

三.事務

1.什麼是事務

  • 事務是由一條或多條SQL語句組成的邏輯執行單元, 能夠比喻成一個容器, 裏面放的就是一堆SQL語句, 這些語句要麼所有執行成功, 要麼一個都沒法執行成功(原子性)

2.爲何使用事務

  • 對數據進行一系列的操做的時候, 爲了防止這些操做中部分操做成功而另外一些操做失敗, 從而形成數據的不正確性, 這個時候咱們就須要使用事務將其回滾到原來的狀態

3.事務的四大特徵 (ACID)

  • 原子性(Atomicity) : 事務是一段程序的最小執行單元, 不可再分(就如同天然界的原子不可再分), 因此事務中的操做要麼都成功, 要麼都失敗
  • 一致性(Consistency) : 事務的執行, 必須使數據庫從一個一致性狀態, 變成另外一個一致性狀態, 一致性是經過原子性來保證的
  • 隔離性(Lsolation) : 各個事務的執行互不干擾, 任意一個事務的內部操做對其餘併發的事務, 都是隔離的; 也就是說 : 併發執行的事務之間不能看到對方的中間狀態, 併發執行的事務之間不能相互影響
  • 持續性(Durability) : 也叫"持久性", 指事務一旦提交, 對數據的任何改變都記錄到永久存儲器中, 一般是物理數據庫

4.如何使用事務

  • 關鍵字
🍎開啓事務
begin;  # 或者下面的語句  
start transaction;

🍎事務回滾(回滾到以前的狀態,並關閉事務)
rollback;  # 回滾 + 關閉

🍎事務提交(將修改提交,並關閉事務)
commit;    # 提交 + 關閉

由上面關鍵字能夠看出, 一個事務的開始對應一個回滾或者提交, 以後就須要從新開啓事務linux

  • 銀行餘額示例
🍎先建立一個用戶餘額表並插入記錄
create table user(
    id int primary key auto_increment,
    name varchar(16) not null,
    balance int not null
);

insert user(name,balance) value
    ("shawn",150000),
    ("song",20000),
    ("xing",520022),
    ("hai",10000);

select * from user;  # 查看一下全部記錄

🍎開啓事務
begin;  # 或者 start transaction;

🍎更新記錄
update user set balance=100 where name="shawn";
update user set balance=100 where name="song";
update user set balance=100 where name="xing";
update user set balance=200 where name="hai";

select * from user;  # 查看一下是否修改爲功

🍎事務回滾
rollback;  # 回滾以後, 該事務就關閉了
select * from user;  # 查看一下是否回滾到原來的數據

🍎再開啓一個事務
begin;

🍎再次對數據進行更新
update user set balance=200 where name="shawn";
update user set balance=200 where name="song";
commit;  # 事務提交, 並關閉了該事務
select * from user;  # 查看數據的變化

rollback;  # 再次使用事務回滾將不在起做用, 由於事務已經關閉了 
select * from user;

image-20210214124605661

image-20210214124833697

image-20210214125609578

四.存儲過程

1.什麼是存儲過程

  • 存儲過程當中包含了一系列的 SQL 語句, 就相似於 Python 中定義的函數, 經過調用存儲過程名(函數名)來執行其內部的一堆 sql 語句(Python代碼)

2.使用存儲過程的優缺點

  • 優勢 :
    • 用於替代程序寫的 SQL 語句, 實現程序與 SQL 語句的解耦
    • 基於網絡的傳輸, 只傳"存儲過程名"比傳一堆的 SQL 語句的數據量小的多
  • 缺點 :
    • 程序的可擴展性很是低

3.應用程序與數據庫結合使用的三種開發模式

  • 第一種
"應用程序" : 程序員本身寫代碼開發
"mysql" : 提早寫好的存儲過程, 提供給程序來調用

🔰優勢 : 提高了開發效率, 執行效率提高(只傳輸'存儲過程名')
🔰缺點 : 可擴展性查, 可能使用者的一些變更就須要修改整個存儲過程
  • 第二種
程序員在開發應用程序的過程當中涉及到的數據庫操做也是本身手動編寫

🔰優勢 : 擴展性很高
🔰缺點 : 開發效率低, 編寫SQL語句太過繁瑣, 且有些重複, 後期維護也不方便
  • 第三種
程序員開發程序時只寫程序代碼, 而sql語句是基於別人寫好的框架直接拿過來使用 (例如使用ORM框架)

🔰優勢 : 開發效率比第一種和第二種都要高
🔰缺點 : 語句的可擴展性差, 並可能出現效率低下的問題

4.建立存儲過程 (無參)

  • 語法
delimiter %%  # 更換默認結束符
create procedure [存儲過程名]()
begin
    [一堆SQL語句]
end %%
delimiter ;   # 將默認結束符改回來
  • 簡單示例
🍅先建立一個表, 在插入幾條子記錄
create table text(
    id int primary key auto_increment,
    name varchar(100) not null,
    sub_time datetime);
insert text(name,sub_time) value
    ("python詳解",now()),
    ("Java入門",now()),
    ("派大星的故事",now()),
    ("小江放牛羊",now());
    
🍅建立無參存儲過程,對"text"表進行一些操做
delimiter %%
create procedure p01()
begin
    select * from text;
    insert text(name,sub_time) value("殺牛羊手法2",now());
end %% 
delimiter ;
	
🔰在"mysql"中調用
call p01();

🔰在"Python"中的"pymysql"中調用
# 首先導入模塊並鏈接數據庫
import pymysql

conn = pymysql.connect(
    host="127.0.0.1",
    port=3306,
    user="root",
    password="123456",
    database="test03",
    charset="utf8"
)
# 獲得遊標
cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
cursor.callproc("p01")    # 調用存儲過程
print(cursor.fetchall())  # 拿到結果並輸出

cursor.close()  # 關閉遊標
conn.close()    # 關閉鏈接

image-20210219133824626

  • mysql 中調用

image-20210219134207642

5.建立存儲過程 (有參)

  • 三種參數類型
"in" : 僅用於傳入參數 (聲明後面的變量爲外部參數)
"out" : 僅用於返回值 (聲明後面的變量是一個返回值,須要使用"set"聲明)
"inout" : 既能夠傳入時使用有能夠返回值時使用 (聲明後面的變量能夠但參數也能夠當返回值,須要"set"聲明)
  • 語法
delimiter %%%  # 修改默認結束符
create procedure [存儲過程名](
    in|out|inout [參數名] [類型],
    .....(能夠多個參數),
    ......
)
begin
    [sql語句]
end %%%
delimiter ;  # 將默認結束符改回來
  • in : 傳入參數示例
🍅建立有參存儲過程
delimiter %%%
create procedure p02(
    in num01 int
)
begin
    select * from text where id=num01;
end %%%
delimiter ;

🍅在"mysql"中直接調用
call p02(4);

🍅"Python"中使用"pymysql"模塊調用
import pymysql

conn = pymysql.connect(
    host="127.0.0.1",
    port=3306,
    user="root",
    password="123456",
    database="test03",
    charset="utf8"
)
cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)

cursor.callproc("p02",(4,))  # 參數傳入的是一個元組
print(cursor.fetchall())

cursor.close()
conn.close()

image-20210221145657543

image-20210221150225494

  • out : 返回值示例 (in+out)
🍅建立有參存儲過程
delimiter %%%
create procedure p03(
    in num01 int,
    out res01 int
)
begin
    select * from text where id=num01;
    set res01=num01+1;
end %%%
delimiter ;

🍅在"mysql"中調用
call p03(4,@res01);  # @res01 表示定義一個全局變量來接收返回值
select @res01;       # 查看這個返回值

🍅在"python"中使用"pymysql"調用
import pymysql

conn = pymysql.connect(
    host="127.0.0.1",
    port=3306,
    user="root",
    password="123456",
    database="test03",
    charset="utf8"
)
cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
res = ""
cursor.callproc("p03", (4, res))  # 第二個參數是用來接收返回值的
print(cursor.fetchall())

cursor.execute("select @_p03_0,@_p03_1;")  # "@_p03_0"表明的是傳入的第一個參數,"@_p03_1"表明的是第二的參數,也就是返回值
print(cursor.fetchall())

cursor.close()
conn.close()

image-20210221154642918

image-20210221155621452

  • inout : 能傳能返回示例
🍅建立存儲過程
delimiter %%%
create procedure p04(
    inout num01 int
)
begin
    select * from text where id>num01;
    set num01=num01+num01;
end %%%
delimiter ;

🍅在"mysql"中調用
set @res=2;     # 先定義一個全局變量
call p04(@res); # 而後傳進去,一方面當參數, 一方面接收返回值
select @res     # 查看這個返回值

🍅在"Python"使用"pymysql"調用
import pymysql

conn = pymysql.connect(
    host="127.0.0.1",
    port=3306,
    user="root",
    password="123456",
    database="test03",
    charset="utf8"
)
cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
res = 2  # 定義一個變量
cursor.callproc("p04", (res,))     # 傳入這個變量,可當參數,也可接收返回值 
print(cursor.fetchall())

cursor.execute("select @_p04_0;")  # 查看返回值
print(cursor.fetchall())

cursor.close()
conn.close()

image-20210221161216644

image-20210221161438446

6.刪除存儲過程

  • 語法
drop procedure [存儲過程名];
  • 示例
drop procedure p01;

五.函數

1.什麼是函數

  • 上面介紹的存儲過程相似於 python 中的自定義的函數
  • 而這裏的函數指的是 mysql 提供的內置函數

2.經常使用內置函數介紹

👉🏻mysql 內置函數官方文檔👈🏻程序員

👉🏻mysql 內置函數中文文檔👈🏻web

  • 數學函數
ROUND(x,y)  # 返回參數x的四捨五入的有y位小數的值
RAND()      # 返回 0 到1內的隨機值,能夠經過提供一個參數(種子)使RAND()隨機數生成器生成一個指定的值
  • 聚合函數(經常使用於GROUP BY從句的SELECT查詢中) 👉🏻使用示例
AVG(col)    # 返回指定列的平均值
COUNT(col)  # 返回指定列中非NULL值的個數
MIN(col)    # 返回指定列的最小值
MAX(col)    # 返回指定列的最大值
SUM(col)    # 返回指定列的全部值之和
GROUP_CONCAT(col) # 返回由屬於一組的列值鏈接組合而成的結果
  • 字符串函數
CHAR_LENGTH(str)       # 返回值爲字符串str 的長度,長度的單位爲字符,一個多字節字符算做一個單字符。
CONCAT(str1,str2,...)  # 字符串拼接,若有任何一個參數爲NULL,則返回值爲 NULL
CONCAT_WS(separator,str1,str2,...)  # 字符串拼接(自定義鏈接符)
CONCAT_WS()  # 不會忽略任何空字符串 (然而會忽略全部的 NULL)
CONV(N,from_base,to_base)  # 進制轉換
    例如:SELECT CONV('a',16,2); 表示將 a 由16進制轉換爲2進制字符串表示
FORMAT(X,D)  # 將數字X 的格式寫爲'#,###,###.##',以四捨五入的方式保留小數點後 D 位,並將結果以字符串的形式返回。若 D 爲 0,則返回結果不帶有小數點,或不含小數部分
    例如:SELECT FORMAT(12332.1,4); 結果爲: '12,332.1000'
INSERT(str,pos,len,newstr)  # 在str的指定位置插入字符串, pos:要替換位置其實位置, len:替換的長度, newstr:新字符串
    特別的:若是pos超過原字符串長度,則返回原字符串;若是len超過原字符串長度,則由新字符串徹底替換
INSTR(str,substr) # 返回字符串 str 中子字符串的第一個出現位置
LEFT(str,len)     # 返回字符串str 從開始的len位置的子序列字符
LOWER(str)        # 變小寫
UPPER(str)        # 變大寫
REVERSE(str)      # 返回字符串 str ,順序和字符順序相反。
SUBSTRING(str,pos) , SUBSTRING(str FROM pos) SUBSTRING(str,pos,len) , SUBSTRING(str FROM pos FOR len)  # 不帶有len 參數的格式從字符串str返回一個子字符串,起始於位置 pos。帶有len參數的格式從字符串str返回一個長度同len字符相同的子字符串,起始於位置 pos。 使用 FROM的格式爲標準 SQL 語法。也可能對pos使用一個負值。倘若這樣,則子字符串的位置起始於字符串結尾的pos 字符,而不是字符串的開頭位置。在如下格式的函數中能夠對pos 使用一個負值
mysql> SELECT SUBSTRING('Quadratically',5);
-> 'ratically'
mysql> SELECT SUBSTRING('foobarbar' FROM 4);
-> 'barbar'
mysql> SELECT SUBSTRING('Quadratically',5,6);
-> 'ratica'
mysql> SELECT SUBSTRING('Sakila', -3);
-> 'ila'
mysql> SELECT SUBSTRING('Sakila', -5, 3);
-> 'aki'
mysql> SELECT SUBSTRING('Sakila' FROM -4 FOR 2);
-> 'ki'
  • 日期和時間函數
CURDATE()或CURRENT_DATE()  # 返回當前的日期
CURTIME()或CURRENT_TIME()  # 返回當前的時間
DAYOFWEEK(date)   # 返回date所表明的一星期中的第幾天(1~7)
DAYOFMONTH(date)  # 返回date是一個月的第幾天(1~31)
DAYOFYEAR(date)   # 返回date是一年的第幾天(1~366)
DAYNAME(date)     # 返回date的星期名,如:SELECT DAYNAME(CURRENT_DATE);
FROM_UNIXTIME(ts,fmt)  # 根據指定的fmt格式,格式化UNIX時間戳ts
HOUR(time)    # 返回time的小時值(0~23)
MINUTE(time)  # 返回time的分鐘值(0~59)
MONTH(date)   # 返回date的月份值(1~12)
MONTHNAME(date)        # 返回date的月份名,如:SELECT MONTHNAME(CURRENT_DATE);
NOW()         # 返回當前的日期和時間
QUARTER(date) # 返回date在一年中的季度(1~4),如SELECT QUARTER(CURRENT_DATE);
WEEK(date)    # 返回日期date爲一年中第幾周(0~53)
YEAR(date)    # 返回日期date的年份(1000~9999)
  • 加密函數
MD5()  # 計算字符串str的MD5校驗和
PASSWORD(str)  # 返回字符串str的加密版本,這個加密過程是不可逆轉的,和UNIX密碼加密過程使用不一樣的算法
  • 控制流函數
CASE WHEN[test1] THEN [result1]...ELSE [default] END      # 若是testN是真,則返回resultN,不然返回default
CASE [test] WHEN[val1] THEN [result]...ELSE [default]END  # 若是test和valN相等,則返回resultN,不然返回default
IF(test,t,f)       # 若是test是真,返回t;不然返回f
IFNULL(arg1,arg2)  # 若是arg1不是空,返回arg1,不然返回arg2
NULLIF(arg1,arg2)  # 若是arg1=arg2返回NULL;不然返回arg1

ps : 流程控制練習算法

🍎準備表 : 將下面數據複製到"sql"後綴的文件中
/*
Navicat MySQL Data Transfer

Source Server         : localhost_3306
Source Server Version : 50720
Source Host           : localhost:3306
Source Database       : student

Target Server Type    : MYSQL
Target Server Version : 50720
File Encoding         : 65001

Date: 2018-01-02 12:05:30
*/

SET FOREIGN_KEY_CHECKS=0;

-- ----------------------------
-- Table structure for course
-- ----------------------------
DROP TABLE IF EXISTS `course`;
CREATE TABLE `course` (
  `c_id` int(11) NOT NULL,
  `c_name` varchar(255) DEFAULT NULL,
  `t_id` int(11) DEFAULT NULL,
  PRIMARY KEY (`c_id`),
  KEY `t_id` (`t_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of course
-- ----------------------------
INSERT INTO `course` VALUES ('1', 'python', '1');
INSERT INTO `course` VALUES ('2', 'java', '2');
INSERT INTO `course` VALUES ('3', 'linux', '3');
INSERT INTO `course` VALUES ('4', 'web', '2');

-- ----------------------------
-- Table structure for score
-- ----------------------------
DROP TABLE IF EXISTS `score`;
CREATE TABLE `score` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `s_id` int(10) DEFAULT NULL,
  `c_id` int(11) DEFAULT NULL,
  `num` double DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of score
-- ----------------------------
INSERT INTO `score` VALUES ('1', '1', '1', '79');
INSERT INTO `score` VALUES ('2', '1', '2', '78');
INSERT INTO `score` VALUES ('3', '1', '3', '35');
INSERT INTO `score` VALUES ('4', '2', '2', '32');
INSERT INTO `score` VALUES ('5', '3', '1', '66');
INSERT INTO `score` VALUES ('6', '4', '2', '77');
INSERT INTO `score` VALUES ('7', '4', '1', '68');
INSERT INTO `score` VALUES ('8', '5', '1', '66');
INSERT INTO `score` VALUES ('9', '2', '1', '69');
INSERT INTO `score` VALUES ('10', '4', '4', '75');
INSERT INTO `score` VALUES ('11', '5', '4', '66.7');

-- ----------------------------
-- Table structure for student
-- ----------------------------
DROP TABLE IF EXISTS `student`;
CREATE TABLE `student` (
  `s_id` varchar(20) NOT NULL,
  `s_name` varchar(255) DEFAULT NULL,
  `s_age` int(10) DEFAULT NULL,
  `s_sex` char(1) DEFAULT NULL,
  PRIMARY KEY (`s_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of student
-- ----------------------------
INSERT INTO `student` VALUES ('1', '魯班', '12', '男');
INSERT INTO `student` VALUES ('2', '貂蟬', '20', '女');
INSERT INTO `student` VALUES ('3', '劉備', '35', '男');
INSERT INTO `student` VALUES ('4', '關羽', '34', '男');
INSERT INTO `student` VALUES ('5', '張飛', '33', '女');

-- ----------------------------
-- Table structure for teacher
-- ----------------------------
DROP TABLE IF EXISTS `teacher`;
CREATE TABLE `teacher` (
  `t_id` int(10) NOT NULL,
  `t_name` varchar(50) DEFAULT NULL,
  PRIMARY KEY (`t_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of teacher
-- ----------------------------
INSERT INTO `teacher` VALUES ('1', '大王');
INSERT INTO `teacher` VALUES ('2', 'alex');
INSERT INTO `teacher` VALUES ('3', 'egon');
INSERT INTO `teacher` VALUES ('4', 'peiqi');

image-20210222162718945

🍎建立一個庫,並導入該文件
create database school_test;  # 建立一個庫
use school_test
source J:\MySql\mysql-5.6.48-winx64\data\sql_file\school_test.sql  # 導入該文件(須要文件路徑)
show tables;  # 查看是否導入成功
select * from student;
select * from teacher;

image-20210222162840937

image-20210222164519949

🍎統計各科各分數段人數, 顯示格式:課程ID,課程名稱,[100-85],[85-70],[70-60],[ <60]
# 以各學科分組,顯示課程ID和課程名字,因而須要將course與score鏈表,使用流程控制+sum()函數統計各分數段的人數
select course.c_id,course.c_name,
    sum(case when (num between 85 and 100) then 1 else 0 end) as "[100-85]",
    sum(case when (num between 70 and 84) then 1 else 0 end) as "[85-70]",
    sum(case when (num between 60 and 69) then 1 else 0 end) as "[70-60]",
    sum(case when num<60 then 1 else 0 end) as "[ <60]"
    from score,course where score.c_id=course.c_id
    group by score.c_id;

image-20210222171244181

3.重點函數 : date_format( ) 介紹

  • 語法
select date_format([date],[format])  # 將傳入的時間(date)按照傳入的格式(format)進行轉換
  • 基本使用示例
select date_format("2021-02-22","%W %M %Y") as time;  # 星期 月 年
select date_format("2020-01-25 11:14:23","%H:%i:%s") as time;  # 時 分 秒
select date_format("2020-01-25 11:14:23","%D %y %d %m %b %j") as time;  # 日 年 日 月 月 日
select date_format("1111-11-11 11:11:11","%H %k %I %r %T %S %w")as time;

image-20210222150952750

  • 示例
🍅將"text"表中的"sub_time"提取出來轉換成"時分秒"格式進行分組,並統計個數
select * from text;
select date_format(sub_time,"%H:%i:%s") as time,count(id)
    from text
    group by time;

image-20210222153217139

4.自定義函數 (刪除 + 調用)

自定義函數不一樣於存儲過程, 函數中不能寫 sql 語句(不然報錯), 函數僅僅是 sql 中被應用的功能; 若是須要在 begin...end 中放置 sql 語句, 使用存儲過程就好了sql

  • 語法
delimiter %%%
create function [函數名](
    [參數1] [類型],
    [參數2] [類型])
returns [類型]
begin
    [一系列代碼]
end %%%
delimiter ;
  • 示例1
🍅定義一個函數(求兩個數和)
delimiter %%%           # 修改默認結束符
create function f01(
    num01 int,
    num02 int)          # 定義參數以及類型
returns int             # 設置返回值的類型爲 int
begin
    declare num03 int;  # 聲明變量 num03 爲 int 類型
    set num03=num01+num02;
    return(num03);
end %%%
delimiter ;             # 將默認結束符修改回來

🍅調用自定義函數
select f01(2,4);  # 查詢+調用
select f01(2,4) into @res;  # 調用並將返回值給變量 @res
select @res;  # 查看變量值

image-20210222173732567

  • 示例二
🍅定義一個函數
delimiter %%%
create function f012(
    num01 int)
returns int
begin
    declare res int default 0;  # 聲明變量 res 爲 int 類型,若是傳入的不是 int,默認返回 0
    if num01 = 10 then
        set res = num01*num01;
    elseif num01 = 20 then
        set res = num01*num01;
    elseif num01 = 30 then
        set res = num01*num01;
    else
        set res = num01;
    end if;
    return(res);
end %%%
delimiter ;

🍅調用
select f012(10);
select f012(20);
select f012(30);
select f012(40);
select f012("ad");

image-20210222175224690

  • 刪除函數
drop function [函數名];
drop function f012;

六.流程控制

1.條件語句 : if

delimiter %%%
create procedure p01(in num int)
begin
    if num = 1 then
        select 1;
    elseif num = 2 then
        select 2;
    else select 3;
    end if;
end %%%
delimiter ;

image-20210222193158589

2.循環語句

  • while 循環
delimiter %%%
create procedure p02()
begin
    declare num int;
    set num = 0;
    while num < 3 do
        select num;
        set num = num + 1;
    end while;
end %%%
delimiter ;

image-20210222200318882

  • repeat 循環
delimiter %%%
create procedure p03()
begin 
    declare num int;
    set num = 0;
    repeat
        select num;
        set num = num + 1;
        until num > 3  # 結束條件:當num>3時結束
    end repeat;
end %%%
delimiter ;

image-20210222202115615

  • loop 循環
delimiter %%%
create procedure p04()
begin
    declare num int default 0;
    myloop:loop
        set num=num+1;
        if num>=3 then
            leave myloop;  # 當 num>=3 結束循環
        end if;
        select num;
    end loop myloop;
end %%%
delimiter ;

image-20210222204742170

---end---數據庫

相關文章
相關標籤/搜索