資料庫系統原理之資料庫編程

来源:https://www.cnblogs.com/QiaoPengjun/archive/2023/03/22/17244918.html
-Advertisement-
Play Games

資料庫編程 第一節 存儲過程 一、存儲過程的基本概念 存儲過程是一組為了完成某項特定功能的 SQL 語句集,其實質上就是一段存儲在資料庫中的代碼,它可以由聲明式的 SQL 語句(如 CREATE、UPDATE 和 SELECT 等語句)和過程式 SQL 語句(如 IF...THEN...ELSE 控 ...


資料庫編程

第一節 存儲過程

一、存儲過程的基本概念

  • 存儲過程是一組為了完成某項特定功能的 SQL 語句集,其實質上就是一段存儲在資料庫中的代碼,它可以由聲明式的 SQL 語句(如 CREATE、UPDATE 和 SELECT 等語句)和過程式 SQL 語句(如 IF...THEN...ELSE 控制結構語句)組成。
  • 這組語句集經過編譯後會存儲在資料庫中,用戶只需通過指定存儲過程的名字並給定參數(如果該存儲過程帶有參數),即可隨時調用並執行它,而不必重新編譯,因此這種通過定義一段程式存儲在資料庫中的方式,可加大資料庫操作語句的執行效率。
  • 使用存儲過程通常具有以下一些好處:
    • 可增強SQL語言的功能和靈活性
    • 良好的封裝性
    • 高性能
    • 可減少網路流量
    • 存儲過程可作為一種安全機制來確保資料庫的安全性和數據的完整性

二、創建存儲過程

DELIMITER 命令的使用語法格式是:

DELIMITER $$
  • $$ 是用戶定義的結束符,通常這個符號可以是一些特殊的符號,例如兩個“#”,或兩個“¥”等
  • 當使用 DELIMITER 命令時,應該避免使用反斜杠(“\”)字元,因為它是MySQL的轉義字元

例子:將 MySQL 結束符修改為兩個感嘆號“!!”。

mysql> DELIMITER !!

換回預設的分行“;”

mysql> DELIMITER ;

創建存儲過程

CREATE PROCEDURE sp_name ([proc_parameter[,...]])
	routine_body

"proc_parameter" 的語法格式:

[IN | OUT | INOUT] param_name type

# 參數的取名不要與數據表的列名相同
  • 語法項“routine_body” 表示存儲過程的主體部分,也稱為存儲過程體,其包含了在過程調用的時候必須執行的SQL語句。
  • 這個部分以關鍵字“BEGIN” 開始,以關鍵字“END”結束。
  • 如若存儲過程體中只有一條 SQL語句時,可以省略 BEGIN...END 標誌。
  • 在存儲過程體中,BEGIN...END 複合語句可以嵌套使用

例子:在資料庫 mysql_test 中創建一個存儲過程,用於實現給定表 customers 中一個客戶 id 號即可修改表 customers 中該客戶的性別為一個指定的性別。

➜ mysql -uroot -p
Enter password:
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 1850
Server version: 8.0.32 Homebrew

Copyright (c) 2000, 2023, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> use mysql_test;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
mysql> delimiter $$
mysql> create procedure sp_update_sex(in cid int,in csex char(1))
    -> begin
    -> update customers set cust_sex=csex where cust_id=cid;
    -> end $$
Query OK, 0 rows affected (0.03 sec)

mysql>

三、存儲過程體

1 局部變數

  • 用來存儲存儲過程體中的臨時結果
DECLARE var_name[,...] type [DEFAULT value]

例子:聲明一個整形局部變數 cid。

DECLARE cid INT(10);
  • 局部變數只能在存儲過程體的 BEGIN...END 語句塊中聲明
  • 局部變數必須在存儲過程體的開頭出聲明
  • 局部變數的作用範圍僅限於聲明它的 BEGIN...END 語句塊,其他語句塊中的語句不可以使用它
  • 局部變數不同於用戶變數,兩者的區別是:
    • 局部變數聲明時,在其前面沒有使用 @ 符號,並且它只能被聲明它的 BEGIN...END 語句塊中的語句所使用
    • 用戶變數在聲明時,會在其名稱前面使用 @ 符號,同時已聲明的用戶變數存在於整個會話之中

2 SET 語句

SET var_name = expr [, var_name = expr] ...

例子:為聲明的局部變數 cid 賦予一個整數值 910

SET cid=910;

3 SELECT...INTO 語句

  • 把選定列的值直接存儲到局部變數中
SELECT col_name [,...] INTO var_name[,...] table_expr
  • 存儲過程體中的 SELECT...INTO 語句返回的結果集只能有一行數據

4 流程式控制制語句

(1)條件判斷語句
  • 常用的條件判斷語句有 IF...THEN...ELSE 語句和 CASE 語句。
  • 它們的使用語法及方式類似於高級程式設計語言。
(2)迴圈語句
  • 常用的迴圈語句有 WHILE 語句、REPEAT 語句和 LOOP 語句。
  • 它們的使用語法及方式同樣類似於高級程式設計語言。
  • 迴圈語句中還可以使用 ITERATE 語句,但它只能出現在迴圈語句的 LOOP、REPEAT 和 WHILE 子句中,用於表示退出當前迴圈,且重新開始一個迴圈。

5 游標

  • 在MySQL中,一條 SELECT...INTO 語句成功執行後,會返回帶有值的一行數據,這行數據可以被讀取到存儲過程中進行處理。
  • 然而,在使用 SELECT 語句進行數據檢索時,若該語句成功被執行,則會返回一組稱為結果集的數據行,該結果集中可能擁有多行數據,這些數據無法直接被一行一行地進行處理,此時就需要使用游標。
  • 游標是一個被 SELECT 語句檢索出來的結果集。
  • 在存儲了游標後,應用程式或用戶就可以根據需要滾動或瀏覽其中的數據。

在MySQL中,使用游標的具體步驟如下:

(1)聲明游標
DECLARE cursor_name CURSOR FOR select_statement
  • 語法項“select_statement”用於指定一個 SELECT 語句,其會返回一行或多行的數據,且需註意此處的 SELECT 語句不能有 INTO 子句。
(2)打開游標
OPEN cursor_name
(3)讀取數據
FETCH cursor_name INTO var_name [, var_name] ...
  • 游標相當於一個指針,它指向當前的一行數據。
(4)關閉游標
CLOSE cursor_name
  • 如果沒有明確關閉游標,MySQL將會在到達 END 語句時自動關閉它。
  • 在一個游標被關閉後,如果沒有重新被打開,則不能被使用。
  • 對於聲明過的游標,則不需要再次聲明,可直接使用 OPEN 語句打開。

例子:在資料庫 mysql_test 中創建一個存儲過程,用於計算表 customers 中數據行的行數。

首先,在MySQL命令行客戶端輸入如下 SQL語句創建存儲過程 sq_sumofrow:

➜ mysql -uroot -p
Enter password:
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 2286
Server version: 8.0.32 Homebrew

Copyright (c) 2000, 2023, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> use mysql_test;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
mysql> delimiter $$
mysql> create procedure sp_sumofrow(OUT ROWS INT)
    -> begin
    -> declare cid int;
    -> declare found boolean default true;
    -> declare cur_cid cursor for
    -> select cust_id from customers;
    -> declare continue handler for not found
    -> set found=false;
    -> set rows=0;
    -> open cur_cid;
    -> fetch cur_cid into cid;
    -> while found do
    -> set rows=rows+1;
    -> fetch cur_cid into cid;
    -> end while;
    -> close cur_cid;
    -> end$$
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'ROWS INT)
begin
declare cid int;
declare found boolean default true;
declare cur' at line 1
mysql> 


mysql> CREATE PROCEDURE sp_sumofrow(OUT ROWS INT)
    -> BEGIN
    -> DECLARE cid INT;
    -> DECLARE FOUND BOOLEAN DEFAULT TRUE;
    -> DECLARE cur_cid CURSOR FOR
    -> SELECT cust_id FROM customers;
    -> DECLARE CONTINUE HANDLER FOR NOT FOUND
    -> SET FOUND=FALSE;
    -> SET ROWS=0;
    -> OPEN cur_cid;
    -> FETCH cur_cid INTO cid;
    -> WHILE FOUND DO
    -> SET ROWS=ROWS+1;
    -> FETCH cur_cid INTO cid;
    -> END WHILE;
    -> CLOSE cur_cid;
    -> END$$
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'ROWS INT)
BEGIN
DECLARE cid INT;
DECLARE FOUND BOOLEAN DEFAULT TRUE;
DECLARE cur' at line 1
mysql>


mysql> CREATE PROCEDURE sp_sumofrow(OUT `ROWS` INT) BEGIN DECLARE cid INT; DECLARE FOUND BOOLEAN DEFAULT TRUE; DECLARE cur_cid CURSOR FOR SELECT cust_id FROM customers; DECLARE CONTINUE HANDLER FOR NOT FOUND SET FOUND=FALSE; SET `ROWS`=0; OPEN cur_cid; FETCH cur_cid INTO cid; WHILE FOUND DO SET `ROWS`=`ROWS`+1; FETCH cur_cid INTO cid; END WHILE; CLOSE cur_cid; END$$
Query OK, 0 rows affected (0.01 sec)

mysql>

然後,在 MySQL 命令行客戶端輸入如下 SQL語句對存儲過程 sp_sumofrow 進行調用:

mysql> call sp_sumofrow(@rows);
    ->
    ->
    -> $$
Query OK, 0 rows affected (0.01 sec)


mysql> delimiter ;
mysql> select @rows;
+-------+
| @rows |
+-------+
|     4 |
+-------+
1 row in set (0.00 sec)

mysql>

最後,查看調用存儲過程 sp_sumofrow後的結果:

mysql> select @rows;
+-------+
| @rows |
+-------+
|     4 |
+-------+
1 row in set (0.00 sec)

mysql>

由此例可以看出:

  • 定義了一個 CONTINUE HANDLER 句柄,它是在條件出現時被執行的代碼,用於控制迴圈語句,以實現游標的下移
  • DECLARE 語句的使用存在特定的次序,即用 DECLARE 語句定義的局部變數必須在定義任意游標或句柄之前定義,而句柄必須在游標之後定義,否則系統會出現錯誤信息。

在使用游標的過程中,需要註意以下幾點:

  • 游標只能用於存儲過程或存儲函數中,不能單獨在查詢操作中使用。
  • 在存儲過程或存儲函數中可以定義多個游標,但是在一個 BEGIN...END 語句塊中每一個游標的名字必須是唯一的。
  • 游標不是一條 SELECT 語句,是被 SELECT 語句檢索出來的結果集。

四、調用存儲過程

CALL sp_name([parameter[,...]])
CALL sp_name[()]
  • 當調用沒有參數的存儲過程時,使用 CALL sp_name() 語句與使用 CALL sp_name 語句是相同的。

例子:調用資料庫 mysql_test 中的存儲過程 sp_update_sex,將客戶 id 號位 909 的客戶性別修改為男性“M”。

mysql> call sp_update_sex(909,'M');
Query OK, 0 rows affected (0.00 sec)

mysql>

五、刪除存儲過程

DROP PROCEDURE [IF EXISTS] sp_name

例子:刪除資料庫 mysql_test 中的存儲過程 sp_update_sex。

mysql> DROP PROCEDURE sp_update_sex;
Query OK, 0 rows affected (0.01 sec)

mysql>

第二節 存儲函數

存儲函數與存儲過程的區別:

  • 存儲函數不能擁有輸出參數,這是因為存儲函數自身就是輸出參數;而存儲過程可以擁有輸出參數。
  • 可以直接對存儲函數進行調用,且不需要使用 CALL 語句;而對存儲過程的調用,需要使用 CALL 語句。
  • 存儲函數中必須包含一條 RETURN 語句,而這條特殊的SQL語句不允許包含於存儲過程中。

一、創建存儲函數

CREATE FUNCTION sp_name ([func_parameter[,...]])
	RETURNS type
	routine_body

其中,語法項“func_parameter”的語法格式是:

param_name type
  • 存儲函數不能與存儲過程具有相同的名字。
  • 存儲函數體中還必須包含一個 RETURN value 語句,其中 value 用於指定存儲函數的返回值。

例子:在資料庫 mysql_test 中創建一個存儲函數,要求該函數能根據給定的客戶 id 號返回客戶的性別,如果資料庫中沒有給定的 id 號,則返回“沒有該客戶”。

➜ mysql -uroot -p
Enter password:
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 659
Server version: 8.0.32 Homebrew

Copyright (c) 2000, 2023, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> use mysql_test;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
mysql> DELIMITER $$
mysql> CREATE FUNCTION fn_search(cid INT)
    -> RETURNS CHAR(2)
    -> DETERMINISTIC
    -> BEGIN
    -> DECLARE SEX CHAR(2);
    -> SELECT cust_sex INTO SEX FROM customers
    -> WHERE cust_id=cid;
    -> IF SEX IS NULL THEN
    -> RETURN(SELECT '沒有該客戶');
    -> ELSE IF SEX='F' THEN
    -> RETURN(SELECT '女');
    -> ELSE RETURN(SELECT '男');
    -> END IF;
    -> END IF;
    -> END $$
Query OK, 0 rows affected (0.02 sec)

mysql>

二、調用存儲函數

SELECT sp_name ([func_parameter[,...]])

例子:調用資料庫 mysql_test 中的存儲函數 fn_search。

mysql> delimiter ;
mysql> SELECT fn_search(904);
+----------------+
| fn_search(904) |
+----------------+
| 男             |
+----------------+
1 row in set (0.00 sec)

mysql>

三、刪除存儲函數

DROP FUNCTION [IF EXISTS] sp_name

例子:刪除資料庫 mysql_test 中的存儲函數 fn_search。

mysql> DROP FUNCTION IF EXISTS fn_search;
Query OK, 0 rows affected (0.00 sec)

mysql>

本文來自博客園,作者:QIAOPENGJUN,轉載請註明原文鏈接:https://www.cnblogs.com/QiaoPengjun/p/17244918.html


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 網上有很多關於使用win10-ssh客戶端登錄linux-ssh服務端的介紹,但很少介紹多台win10-ssh服務端之間互訪的。以下記錄如何免密登錄win10-ssh服務 根據微軟文檔描述,適用於Windows 10 1809 或 Windows Server 2019以上版本 以下內容如果無特別說 ...
  • 故障問題:由於vSphere虛擬化平臺中的一臺VM虛擬機MAC地址與另一VC中的VM衝突需要修改,在VC中刪除VM的網卡並重新添加一張新的虛擬網卡之後,在VM的RHEL系統中配置網卡IP網關之後,發現IP能正常起,但網關無論如何都無法生效,使用ip r命令無法查看到網關。檢查/etc/sysconf ...
  • 前言 Redis之所以被廣泛使用,不只是因為它快,還因為它除了支持最簡單的字元串(String)類型外,它還支持好幾種數據類型: 哈希(Hash) 列表(List) 集合(Set) 有序集合(Sorted Set) 點陣圖 ( Bitmap ) String String為最簡單的類型,一個key對應 ...
  • 一、使用VMware安裝Ubuntu虛擬機 在Linux系統各個發行版中,Ubuntu系統在服務端和桌面端使用占比最高,網路上資料最是齊全,所以這裡使用Ubuntu LTS。 整體的系統安裝文件較大(>1G),這裡採用了迅雷加速下載。迅雷下載地址:下載迅雷工具 下載地址:Download Ubunt ...
  • 網站需求:請給openlab搭建web網站 1.基於功能變數名稱www.openlab.com可以訪問網站內容為 welcome to openlab!!! 2.給該公司創建三個子界面分別顯示學生信息,教學資料和繳費網站,基於www.openlab.com/student 網站訪問學生信息,www.open ...
  • 實驗要求: 1、建立DNS伺服器,負責解析的域為openedu.com 2、要求將MX記錄指向mail.openedu.com,且對應A記錄為本機IP 3、要求將NS記錄指向ns1.openedu.com,且對應A記錄為本機IP 4、建立www的A記錄指向本機IP; 建立ftp對應A記錄為x.x.x ...
  • MySQL基礎:多表查詢 多表關係 概述 ​ 項目開發中,在進行資料庫表結構設計時,會根據業務需求及模塊之間的關係,分析並設計表結構,由於業務之間相互關聯,所以各個表結構之間也存在著各種聯繫,基本上分為三種: 一對多(多對一) 多對多 一對一 一對多(多對一) 案例:部門與員工的關係 關係:一個部門 ...
  • 資料庫系統概述 一、資料庫基本概念 1 數據 數據(Data)是描述事物的符號記錄,是指用物理符號記錄下來的、可以鑒別的信息。 數據以及關於該數據的解釋是密切相關的。 數據的解釋是對數據含義的說明,也稱為數據的語義,即數據所蘊含的信息。 數據與其語義密不可分,沒有語義的數據是沒有意義和不完整的。 數 ...
一周排行
    -Advertisement-
    Play Games
  • GoF之工廠模式 @目錄GoF之工廠模式每博一文案1. 簡單說明“23種設計模式”1.2 介紹工廠模式的三種形態1.3 簡單工廠模式(靜態工廠模式)1.3.1 簡單工廠模式的優缺點:1.4 工廠方法模式1.4.1 工廠方法模式的優缺點:1.5 抽象工廠模式1.6 抽象工廠模式的優缺點:2. 總結:3 ...
  • 新改進提供的Taurus Rpc 功能,可以簡化微服務間的調用,同時可以不用再手動輸出模塊名稱,或調用路徑,包括負載均衡,這一切,由框架實現並提供了。新的Taurus Rpc 功能,將使得服務間的調用,更加輕鬆、簡約、高效。 ...
  • 本章將和大家分享ES的數據同步方案和ES集群相關知識。廢話不多說,下麵我們直接進入主題。 一、ES數據同步 1、數據同步問題 Elasticsearch中的酒店數據來自於mysql資料庫,因此mysql數據發生改變時,Elasticsearch也必須跟著改變,這個就是Elasticsearch與my ...
  • 引言 在我們之前的文章中介紹過使用Bogus生成模擬測試數據,今天來講解一下功能更加強大自動生成測試數據的工具的庫"AutoFixture"。 什麼是AutoFixture? AutoFixture 是一個針對 .NET 的開源庫,旨在最大程度地減少單元測試中的“安排(Arrange)”階段,以提高 ...
  • 經過前面幾個部分學習,相信學過的同學已經能夠掌握 .NET Emit 這種中間語言,並能使得它來編寫一些應用,以提高程式的性能。隨著 IL 指令篇的結束,本系列也已經接近尾聲,在這接近結束的最後,會提供幾個可供直接使用的示例,以供大伙分析或使用在項目中。 ...
  • 當從不同來源導入Excel數據時,可能存在重覆的記錄。為了確保數據的準確性,通常需要刪除這些重覆的行。手動查找並刪除可能會非常耗費時間,而通過編程腳本則可以實現在短時間內處理大量數據。本文將提供一個使用C# 快速查找並刪除Excel重覆項的免費解決方案。 以下是實現步驟: 1. 首先安裝免費.NET ...
  • C++ 異常處理 C++ 異常處理機制允許程式在運行時處理錯誤或意外情況。它提供了捕獲和處理錯誤的一種結構化方式,使程式更加健壯和可靠。 異常處理的基本概念: 異常: 程式在運行時發生的錯誤或意外情況。 拋出異常: 使用 throw 關鍵字將異常傳遞給調用堆棧。 捕獲異常: 使用 try-catch ...
  • 優秀且經驗豐富的Java開發人員的特征之一是對API的廣泛瞭解,包括JDK和第三方庫。 我花了很多時間來學習API,尤其是在閱讀了Effective Java 3rd Edition之後 ,Joshua Bloch建議在Java 3rd Edition中使用現有的API進行開發,而不是為常見的東西編 ...
  • 框架 · 使用laravel框架,原因:tp的框架路由和orm沒有laravel好用 · 使用強制路由,方便介面多時,分多版本,分文件夾等操作 介面 · 介面開發註意欄位類型,欄位是int,查詢成功失敗都要返回int(對接java等強類型語言方便) · 查詢介面用GET、其他用POST 代碼 · 所 ...
  • 正文 下午找企業的人去鎮上做貸後。 車上聽同事跟那個司機對罵,火星子都快出來了。司機跟那同事更熟一些,連我在內一共就三個人,同事那一手指桑罵槐給我都聽愣了。司機也是老社會人了,馬上聽出來了,為那個無辜的企業經辦人辯護,實際上是為自己辯護。 “這個事情你不能怪企業。”“但他們總不能讓銀行的人全權負責, ...