MySQL 存儲過程面試基礎知識總結

文章目錄

  • MySQL 存儲過程面試基礎知識總結
    • 一、存儲過程基礎
      • (一)概述
        • 1.優點
        • 2.缺點
      • (二)創建與調用
        • 1.創建存儲過程
        • 2.調用存儲過程
        • 3.查看存儲過程
        • 4.修改存儲過程
        • 5.存儲過程權限管理
      • (三)參數
        • 1.輸入參數
        • 2.輸出參數
        • 3.輸入輸出參數
      • (四)控制流語句
        • 1.IF - ELSE 語句
        • 2.WHILE 循環語句
        • 3.CASE 語句
        • 4.LOOP 循環
        • 5.REPEAT 循環
      • (五)練習
        • 練習一:創建和調用存儲過程
        • 練習二:使用輸出參數
        • 練習三:控制流語句應用
    • 二、變量
      • (一)局部變量
        • 1.定義
        • 2.聲明
        • 3.賦值
        • 4.作用域
      • (二)全局變量
        • 1.定義
        • 2.聲明
        • 3.賦值
        • 4.作用域
      • (三)示例
        • 1.局部變量示例
        • 2.全局變量示例
      • (四)面試常問問題
        • 1.局部變量和全局變量的區別是什么?
        • 2.如何聲明和使用局部變量?
        • 3.如何查看和設置全局變量的值?
        • 4.在存儲過程中如何使用局部變量?
        • 5.全局變量和局部變量的命名沖突如何解決?
      • 附:【局部變量 用戶定義的變量(帶@的變量) 全局變量 】三者對比
        • 示例代碼
        • 詳細解釋
    • 三、 游標(CURSOR)
      • 定義
      • 聲明
      • 打開游標
      • 獲取數據
      • 關閉游標
      • 示例
    • 四、處理程序(HANDLER)
      • 定義
      • 聲明
      • 示例
    • 五、 事務控制
      • 事務概述
      • BEGIN、COMMIT、ROLLBACK 語句
      • 示例
    • 六、 動態 SQL
      • 動態 SQL 概述
      • PREPARE、EXECUTE、DEALLOCATE PREPARE 語句
      • 示例
    • 八、 存儲過程案例:
      • 批量數據處理示例:批量更新用戶積分
      • 數據校驗示例:校驗用戶輸入數據
      • 復雜業務邏輯封裝示例:計算訂單總金額


MySQL 存儲過程面試基礎知識總結

一、存儲過程基礎

存儲過程(Stored Procedure)是一組 SQL 語句的集合,存儲在數據庫中,通過指定名稱和參數調用執行。它主要用于提高性能、代碼復用和增強安全性。

(一)概述

1.優點
  • 提高性能:存儲過程在數據庫服務器端執行,減少了網絡傳輸的次數。例如,當需要對大量數據進行復雜的查詢和更新操作時,存儲過程可以將這些操作封裝在一起,一次執行完成,大大減少了網絡通信開銷。而且存儲過程在第一次執行時會被編譯,之后的調用可以直接執行編譯后的代碼,提高了執行效率。
  • 代碼復用:可以將常用的 SQL 操作封裝成存儲過程,方便在不同的應用程序和地方調用。比如,一個企業數據庫中,經常需要查詢員工的詳細信息,包括姓名、部門、工資等,將這些查詢操作封裝成存儲過程后,不同的部門在開發自己的應用程序時就可以直接調用這個存儲過程來獲取數據,避免重復編寫代碼。
  • 安全性增強:可以通過存儲過程控制用戶對數據庫的訪問權限。例如,只允許用戶通過特定的存儲過程來修改數據,而不能直接對表進行修改操作,這樣可以防止用戶對數據庫進行不恰當的操作,提高數據庫的安全性。
2.缺點
  • 可移植性差:不同數據庫管理系統(DBMS)的存儲過程語法有所不同。例如,SQL Server 使用 Transact - SQL(T - SQL)語言來編寫存儲過程,而 MySQL 使用自己的存儲過程語法。如果要將一個數據庫從 SQL Server 遷移到 MySQL,存儲過程可能需要重新編寫或修改。
  • 調試困難:存儲過程的調試相對復雜,特別是在存儲過程比較復雜,包含多個分支和循環時。與在應用程序代碼中調試相比,數據庫端的調試工具通常沒有那么強大,很難像在高級語言(如 Java、Python)中那樣方便地設置斷點、查看變量值等。

(二)創建與調用

1.創建存儲過程

在 MySQL 中,創建存儲過程的基本語法如下:

DELIMITER $$CREATE PROCEDURE procedure_name( [ IN | OUT | INOUT ] parameter_name parameter_data_type, ... )
BEGIN-- SQL statements
END$$DELIMITER ;
  • DELIMITER:MySQL 默認的語句分隔符是分號(;)。在存儲過程內部,可能會包含多個 SQL 語句,這些語句也需要用分號分隔。為了避免與存儲過程內部的分號沖突,需要將分隔符改為其他字符(如 $$)。在存儲過程定義完成后,再將分隔符改回默認的分號。
  • IN、OUT、INOUT:用于指定參數的類型。IN 表示輸入參數,OUT 表示輸出參數,INOUT 表示輸入輸出參數。
  • parameter_name 和 parameter_data_type:分別是參數的名稱和數據類型。例如,IN employee_id INT 表示一個名為 employee_id 的輸入參數,數據類型為整數。
  • SQL statements:是存儲過程要執行的 SQL 語句,可以是查詢、插入、更新、刪除等操作。

例如,創建一個存儲過程,用于查詢員工的工資信息:

DELIMITER $$CREATE PROCEDURE GetEmployeeSalary(IN employee_id INT)
BEGINSELECT salaryFROM employeesWHERE employee_id = employee_id;
END$$DELIMITER ;
2.調用存儲過程

調用存儲過程的語法為:

CALL procedure_name(parameter1, parameter2, ...);

對于上面創建的 GetEmployeeSalary 存儲過程,調用它來查詢員工編號為 1001 的員工工資:

CALL GetEmployeeSalary(1001);
3.查看存儲過程

查看某個數據庫下面的存儲過程:

select name from mysql.proc where db='數據庫名';或者select routine_name from information_schema.routines where routine_schema='數據庫名';或者show procedure status where db='數據庫名';

在 MySQL 8.0 及更高版本中,存儲過程和函數的元數據存儲在 INFORMATION_SCHEMA.ROUTINES 表中,而不是 mysql.proc 表中。
在這里插入圖片描述

在這里插入圖片描述

詳細查看存儲過程:
1.SHOW CREATE PROCEDURE 語句

SHOW CREATE PROCEDURE procedure_name;

在這里插入圖片描述

2.INFORMATION_SCHEMA 表

SELECT * FROM INFORMATION_SCHEMA.ROUTINES
WHERE ROUTINE_NAME = 'procedure_name';

在這里插入圖片描述

4.修改存儲過程

刪除并重新創建

DROP PROCEDURE procedure_name;
CREATE PROCEDURE procedure_name ...

使用 ALTER PROCEDURE 語句(MySQL 8.0+)

ALTER PROCEDURE procedure_name ...
5.存儲過程權限管理

授予權限

GRANT EXECUTE ON procedure_name TO 'username'@'host';

撤銷權限

REVOKE EXECUTE ON procedure_name FROM 'username'@'host';

(三)參數

1.輸入參數

輸入參數是調用存儲過程時從外部傳入的參數,存儲過程內部根據這些參數來執行相應的操作。在前面的 GetEmployeeSalary 存儲過程中,employee_id 就是一個輸入參數。

2.輸出參數

輸出參數是存儲過程執行完成后返回給調用者的參數。在 MySQL 中,輸出參數需要在參數定義時加上 OUT 關鍵字。例如,創建一個存儲過程,計算兩個數的和,并將結果通過輸出參數返回:

DELIMITER $$CREATE PROCEDURE AddTwoNumbers(IN number1 INT, IN number2 INT, OUT sum INT)
BEGINSET sum = number1 + number2;
END$$DELIMITER ;

調用這個存儲過程并獲取輸出參數的值:

SET @result = 0;
CALL AddTwoNumbers(5, 3, @result);
SELECT @result AS Sum;
3.輸入輸出參數

輸入輸出參數既可以接收外部傳入的值,也可以在存儲過程執行完成后將修改后的值返回給調用者。在 MySQL 中,輸入輸出參數需要加上 INOUT 關鍵字。例如,創建一個存儲過程,將輸入的數字乘以 2,并將結果返回:

DELIMITER $$CREATE PROCEDURE DoubleNumber(INOUT number INT)
BEGINSET number = number * 2;
END$$DELIMITER ;

調用這個存儲過程:

SET @input_number = 10;
CALL DoubleNumber(@input_number);
SELECT @input_number AS Result;

(四)控制流語句

1.IF - ELSE 語句

用于條件判斷。例如,創建一個存儲過程,根據員工的工資等級(通過輸入參數傳入)來判斷是否發放獎金:

DELIMITER $$CREATE PROCEDURE CheckBonus(IN salary_grade INT)
BEGINIF salary_grade = 1 THENSELECT '發放獎金';ELSESELECT '不發放獎金';END IF;
END$$DELIMITER ;
2.WHILE 循環語句

用于循環操作。例如,創建一個存儲過程,將表中的員工工資依次增加 100,直到工資超過 10000:

DELIMITER $$CREATE PROCEDURE IncreaseSalary()
BEGINDECLARE employee_id INT DEFAULT 1;DECLARE current_salary INT;WHILE TRUE DOSELECT salary INTO current_salaryFROM employeesWHERE employee_id = employee_id;IF current_salary IS NULL THENLEAVE;END IF;IF current_salary < 10000 THENUPDATE employeesSET salary = salary + 100WHERE employee_id = employee_id;END IF;SET employee_id = employee_id + 1;END WHILE;
END$$DELIMITER ;

非常抱歉遺漏了 CASE 語句的介紹。CASE 語句在 MySQL 中用于條件判斷,類似于其他編程語言中的 switch 語句。它可以根據不同的條件執行不同的代碼塊。現在我將補充 CASE 語句的內容,并提供一個示例。

3.CASE 語句

CASE 語句用于根據不同的條件執行不同的代碼塊。它可以根據一個表達式的值選擇執行多個分支中的一個。

CASE 語句的基本語法如下:

CASE case_valueWHEN when_value1 THEN statement1;WHEN when_value2 THEN statement2;...ELSE statementN;
END CASE;
  • case_value:要比較的表達式。
  • when_value:與 case_value 比較的值。
  • statement:當 case_value 等于 when_value 時執行的語句。
  • ELSE:可選,當 case_value 不等于任何 when_value 時執行的語句。

以下是一個使用 CASE 語句的存儲過程示例,根據員工的工資等級(通過輸入參數傳入)來判斷是否發放獎金,并打印相應的消息:

DELIMITER $$CREATE PROCEDURE CheckBonus(IN salary_grade INT)
BEGINCASE salary_gradeWHEN 1 THENSELECT '發放獎金';WHEN 2 THENSELECT '發放小禮品';WHEN 3 THENSELECT '發放感謝信';ELSESELECT '不發放任何獎勵';END CASE;
END$$DELIMITER ;

在這個示例中:

  • CASE salary_grade 表示根據 salary_grade 的值進行條件判斷。
  • WHEN 1 THEN 表示如果 salary_grade 等于 1,則執行 SELECT '發放獎金';
  • WHEN 2 THEN 表示如果 salary_grade 等于 2,則執行 SELECT '發放小禮品';
  • WHEN 3 THEN 表示如果 salary_grade 等于 3,則執行 SELECT '發放感謝信';
  • ELSE 表示如果 salary_grade 不等于 1、2 或 3,則執行 SELECT '不發放任何獎勵';

調用上述存儲過程,傳入不同的 salary_grade 值:

CALL CheckBonus(1); -- 輸出:發放獎金
CALL CheckBonus(2); -- 輸出:發放小禮品
CALL CheckBonus(3); -- 輸出:發放感謝信
CALL CheckBonus(4); -- 輸出:不發放任何獎勵
4.LOOP 循環

語法:

LOOP-- 循環體中的語句
END LOOP;

示例:
以下是一個使用 LOOP 循環的存儲過程示例,該存儲過程將表中的員工工資依次增加 100,直到工資超過 10000:

DELIMITER $$CREATE PROCEDURE IncreaseSalary()
BEGINDECLARE employee_id INT DEFAULT 1;DECLARE current_salary INT;my_loop: LOOPSELECT salary INTO current_salaryFROM employeesWHERE employee_id = employee_id;IF current_salary IS NULL THENLEAVE my_loop;END IF;IF current_salary < 10000 THENUPDATE employeesSET salary = salary + 100WHERE employee_id = employee_id;END IF;SET employee_id = employee_id + 1;END LOOP my_loop;
END$$DELIMITER ;
5.REPEAT 循環

語法:

REPEAT-- 循環體中的語句
UNTIL 條件
END REPEAT;

示例:
以下是一個使用 REPEAT 循環的存儲過程示例,該存儲過程將表中的員工工資依次增加 100,直到工資超過 10000:

DELIMITER $$CREATE PROCEDURE IncreaseSalary()
BEGINDECLARE employee_id INT DEFAULT 1;DECLARE current_salary INT;REPEATSELECT salary INTO current_salaryFROM employeesWHERE employee_id = employee_id;IF current_salary IS NOT NULL THENIF current_salary < 10000 THENUPDATE employeesSET salary = salary + 100WHERE employee_id = employee_id;END IF;ELSELEAVE;END IF;SET employee_id = employee_id + 1;UNTIL current_salary IS NULLEND REPEAT;
END$$DELIMITER ;

(五)練習

練習一:創建和調用存儲過程

創建一個存儲過程,用于查詢指定部門的員工數量。存儲過程名稱為 GetEmployeeCountByDepartment,參數為部門編號(@department_id)。
調用這個存儲過程,查詢部門編號為 10 的員工數量。
答案:

DELIMITER $$CREATE PROCEDURE GetEmployeeCountByDepartment(IN department_id INT)
BEGINSELECT COUNT(*) AS EmployeeCountFROM employeesWHERE department_id = department_id;
END$$DELIMITER ;CALL GetEmployeeCountByDepartment(10);
練習二:使用輸出參數

創建一個存儲過程,用于計算兩個數的乘積,并將結果通過輸出參數返回。存儲過程名稱為 MultiplyTwoNumbers,輸入參數為兩個數字(@number1@number2),輸出參數為乘積(@product)。
調用這個存儲過程,計算 4 和 6 的乘積,并將結果存儲到一個變量中。
答案:

DELIMITER $$CREATE PROCEDURE MultiplyTwoNumbers(IN number1 INT, IN number2 INT, OUT product INT)
BEGINSET product = number1 * number2;
END$$DELIMITER ;SET @result = 0;
CALL MultiplyTwoNumbers(4, 6, @result);
SELECT @result AS Product;
練習三:控制流語句應用

創建一個存儲過程,用于判斷一個數字是否為偶數。如果是偶數,打印“偶數”,否則打印“奇數”。存儲過程名稱為 CheckEvenOdd,輸入參數為數字(@number)。
調用這個存儲過程,判斷數字 7 是否為偶數。
答案:

DELIMITER $$CREATE PROCEDURE CheckEvenOdd(IN number INT)
BEGINIF number % 2 = 0 THENSELECT '偶數';ELSESELECT '奇數';END IF;
END$$DELIMITER ;CALL CheckEvenOdd(7);

二、變量

(一)局部變量

1.定義

局部變量是在存儲過程、函數或語句塊中聲明的變量,其作用域僅限于聲明它的存儲過程、函數或語句塊內部。

2.聲明

使用 DECLARE 語句聲明局部變量:

DECLARE variable_name variable_data_type [DEFAULT default_value];
  • variable_name:變量的名稱,用于在存儲過程中引用該變量。
  • variable_data_type:變量的數據類型,如 INTVARCHARDATE 等。
  • DEFAULT default_value(可選):為變量指定默認值。如果不指定默認值,則變量的初始值為 NULL
3.賦值

可以使用 SET 語句或在 SELECT 語句中使用 INTO 子句為局部變量賦值:

SET variable_name = value;

SELECT column INTO variable_name
FROM table_name
WHERE condition;

示例:

DELIMITER $$CREATE PROCEDURE GetEmployeeSalary(IN employee_id INT)
BEGIN-- 聲明局部變量DECLARE employee_salary DECIMAL(10, 2);-- 使用 SELECT ... INTO ... 語句查詢員工的工資并賦值給局部變量SELECT salary INTO employee_salaryFROM employeesWHERE employee_id = employee_id;-- 輸出查詢結果SELECT employee_salary AS Salary;
END$$DELIMITER ;
4.作用域

局部變量的作用域僅限于聲明它的存儲過程、函數或語句塊內部,存儲過程或函數執行完畢后,局部變量被銷毀。

(二)全局變量

1.定義

全局變量是在整個數據庫會話中有效的變量,其值在會話期間保持不變,直到顯式地更改它。

2.聲明

全局變量不需要顯式聲明,它們是 MySQL 內置的系統變量,通常以 @@ 開頭。例如:

SELECT @@global.variable_name;

SET GLOBAL variable_name = value;
3.賦值

可以使用 SET GLOBAL 語句或 SET @@global.variable_name 語法為全局變量賦值:

SET GLOBAL variable_name = value;

SET @@global.variable_name = value;
4.作用域

全局變量的作用域是整個數據庫會話,所有用戶都可以訪問和修改全局變量的值,但修改后的值僅對當前會話有效,不會影響其他會話。

(三)示例

1.局部變量示例

以下是一個存儲過程示例,展示了如何聲明和使用局部變量:

DELIMITER $$CREATE PROCEDURE CalculateTotal(IN order_id INT, OUT total DECIMAL(10, 2))
BEGIN-- 聲明局部變量DECLARE item_price DECIMAL(10, 2);DECLARE item_quantity INT;DECLARE total_items INT DEFAULT 0;DECLARE total_amount DECIMAL(10, 2) DEFAULT 0.0;-- 查詢訂單中的商品數量SELECT COUNT(*)INTO total_itemsFROM order_itemsWHERE order_id = order_id;-- 遍歷訂單中的每個商品DECLARE item_cursor CURSOR FORSELECT price, quantityFROM order_itemsWHERE order_id = order_id;DECLARE CONTINUE HANDLER FOR NOT FOUNDSET total_items = 0;OPEN item_cursor;fetch_loop: LOOPFETCH item_cursor INTO item_price, item_quantity;IF total_items = 0 THENLEAVE fetch_loop;END IF;-- 計算每個商品的總價并累加到總金額SET total_amount = total_amount + (item_price * item_quantity);END LOOP;CLOSE item_cursor;-- 將總金額賦值給輸出參數SET total = total_amount;
END$$DELIMITER ;

在上述存儲過程中:

  • 使用 DECLARE 聲明了多個局部變量,包括 item_priceitem_quantitytotal_itemstotal_amount
  • 這些變量在存儲過程的邏輯中用于存儲臨時數據,如商品價格、數量、訂單中商品的總數以及訂單的總金額。
  • 變量 total_itemstotal_amount 被賦予了默認值,分別是 00.0
  • 使用 SET 語句為變量賦值,例如 SET total_amount = total_amount + (item_price * item_quantity);
2.全局變量示例

以下是一個示例,展示了如何使用全局變量:

-- 查看全局變量的值
SELECT @@global.max_connections;-- 設置全局變量的值
SET GLOBAL max_connections = 1000;-- 或者
SET @@global.max_connections = 1000;

在上述示例中:

  • 使用 SELECT @@global.max_connections; 查看了全局變量 max_connections 的值。
  • 使用 SET GLOBAL max_connections = 1000;SET @@global.max_connections = 1000; 設置了全局變量 max_connections 的值。

(四)面試常問問題

1.局部變量和全局變量的區別是什么?
  • 作用域:局部變量的作用域僅限于聲明它的存儲過程、函數或語句塊內部;全局變量的作用域是整個數據庫會話。
  • 聲明方式:局部變量使用 DECLARE 語句聲明;全局變量不需要顯式聲明,使用 @@global.variable_nameSET GLOBAL 語句。
  • 賦值方式:局部變量使用 SET 語句或 SELECT ... INTO ... 語句賦值;全局變量使用 SET GLOBAL 語句或 SET @@global.variable_name 語法賦值。
  • 生命周期:局部變量的生命周期與存儲過程或函數的執行周期相同;全局變量的生命周期是整個數據庫會話。
2.如何聲明和使用局部變量?
  • 使用 DECLARE 語句聲明局部變量,例如 DECLARE variable_name variable_data_type [DEFAULT default_value];
  • 使用 SET 語句或 SELECT ... INTO ... 語句為局部變量賦值,例如 SET variable_name = value;SELECT column INTO variable_name FROM table_name WHERE condition;
  • 局部變量的作用域僅限于聲明它的存儲過程、函數或語句塊內部,存儲過程或函數執行完畢后,局部變量被銷毀。
3.如何查看和設置全局變量的值?
  • 使用 SELECT @@global.variable_name; 查看全局變量的值。
  • 使用 SET GLOBAL variable_name = value;SET @@global.variable_name = value; 設置全局變量的值。
4.在存儲過程中如何使用局部變量?
  • 在存儲過程的開始部分使用 DECLARE 語句聲明局部變量。
  • 使用 SET 語句或 SELECT ... INTO ... 語句為局部變量賦值。
  • 在存儲過程的邏輯中通過變量名直接引用和操作局部變量。
5.全局變量和局部變量的命名沖突如何解決?
  • 全局變量和局部變量的命名沖突通常不會發生,因為它們的作用域不同。全局變量以 @@global. 開頭,而局部變量在存儲過程內部聲明和使用。
  • 如果需要在存儲過程中訪問全局變量,可以顯式地使用 @@global. 前綴來區分,例如 SELECT @@global.max_connections;

附:【局部變量 用戶定義的變量(帶@的變量) 全局變量 】三者對比

特性局部變量用戶定義的變量(帶@的變量)全局變量
作用域僅限于聲明它的存儲過程、函數或語句塊內部整個數據庫會話整個數據庫服務器
聲明方式使用DECLARE語句
示例:DECLARE variable_name variable_data_type [DEFAULT default_value];
使用SET語句
示例:SET @variable_name = value;
使用SET GLOBAL語句或SET @@global.語法
示例:SET GLOBAL variable_name = value;SET @@global.variable_name = value;
賦值方式使用SET語句或SELECT ... INTO ...語句
示例:SET variable_name = value;SELECT column INTO variable_name FROM table_name WHERE condition;
使用SET語句
示例:SET @variable_name = value;
使用SET GLOBAL語句或SET @@global.語法
示例:SET GLOBAL variable_name = value;SET @@global.variable_name = value;
生命周期存儲過程或函數執行完畢后銷毀會話結束時銷毀服務器重啟或顯式更改時更新
用途存儲臨時數據,參與計算或作為邏輯控制的依據存儲臨時值,傳遞數據,接收存儲過程的輸出參數配置數據庫服務器的行為,影響所有會話
示例代碼
  • 局部變量示例

    DELIMITER $$
    CREATE PROCEDURE CalculateTotal(IN order_id INT, OUT total DECIMAL(10, 2))
    BEGINDECLARE item_price DECIMAL(10, 2);DECLARE item_quantity INT;DECLARE total_items INT DEFAULT 0;DECLARE total_amount DECIMAL(10, 2) DEFAULT 0.0;-- 其他邏輯...
    END$$
    DELIMITER ;
    
  • 用戶定義的變量(帶@的變量)示例

    SET @result = 0;
    CALL AddTwoNumbers(5, 3, @result);
    SELECT @result AS Sum;
    
  • 全局變量示例

    SELECT @@global.max_connections;
    SET GLOBAL max_connections = 1000;
    
詳細解釋
  1. 作用域

    • 局部變量:僅限于聲明它的存儲過程、函數或語句塊內部。一旦存儲過程或函數執行完畢,局部變量將被銷毀。
    • 用戶定義的變量(帶 @ 的變量):整個數據庫會話。在同一個會話中,這些變量可以跨多個 SQL 語句使用,直到會話結束。
    • 全局變量:整個數據庫服務器。所有會話都可以訪問和修改全局變量的值,修改后會影響所有當前和未來的會話。
  2. 聲明方式

    • 局部變量:使用 DECLARE 語句在存儲過程或函數的開始部分聲明。
    • 用戶定義的變量(帶 @ 的變量):使用 SET 語句在會話中聲明和初始化。
    • 全局變量:使用 SET GLOBAL 語句或 SET @@global. 語法聲明和賦值。
  3. 賦值方式

    • 局部變量:使用 SET 語句或 SELECT ... INTO ... 語句賦值。
    • 用戶定義的變量(帶 @ 的變量):使用 SET 語句賦值。
    • 全局變量:使用 SET GLOBAL 語句或 SET @@global. 語法賦值。
  4. 生命周期

    • 局部變量:存儲過程或函數執行完畢后銷毀。
    • 用戶定義的變量(帶 @ 的變量):會話結束時銷毀。
    • 全局變量:服務器重啟或顯式更改時更新。
  5. 用途

    • 局部變量:用于存儲臨時數據,參與計算或作為邏輯控制的依據。
    • 用戶定義的變量(帶 @ 的變量):用于存儲臨時值,傳遞數據,接收存儲過程的輸出參數。
    • 全局變量:用于配置數據庫服務器的行為,影響所有會話。

三、 游標(CURSOR)

定義

游標(Cursor)是數據庫中一個臨時的工作區,用于存儲和操作查詢結果集中的數據。

聲明

DECLARE cursor_name CURSOR FOR select_statement;

打開游標

OPEN cursor_name;

獲取數據

FETCH cursor_name INTO variable_name [, variable_name ...];

關閉游標

CLOSE cursor_name;

示例

以下是一個使用游標的存儲過程示例,該存儲過程將表中的員工工資依次增加 100,直到工資超過 10000:

DELIMITER $$CREATE PROCEDURE IncreaseSalary()
BEGINDECLARE employee_id INT;DECLARE current_salary INT;DECLARE done INT DEFAULT 0;DECLARE cursor_name CURSOR FORSELECT employee_id, salaryFROM employees;DECLARE CONTINUE HANDLER FOR NOT FOUNDSET done = 1;OPEN cursor_name;my_loop: LOOPFETCH cursor_name INTO employee_id, current_salary;IF done = 1 THENLEAVE my_loop;END IF;IF current_salary < 10000 THENUPDATE employeesSET salary = salary + 100WHERE employee_id = employee_id;END IF;END LOOP my_loop;CLOSE cursor_name;
END$$DELIMITER ;

四、處理程序(HANDLER)

定義

處理程序(Handler)用于捕獲和處理存儲過程或函數執行過程中發生的特定條件或異常。

聲明

DECLARE [CONTINUE | EXIT | UNDO] HANDLER FOR condition-- 處理程序中的語句

示例

以下是一個使用處理程序的存儲過程示例,該存儲過程捕獲了查詢結果為空的情況:

DELIMITER $$CREATE PROCEDURE GetEmployeeSalary(IN employee_id INT)
BEGINDECLARE employee_salary DECIMAL(10, 2);DECLARE done INT DEFAULT 0;DECLARE CONTINUE HANDLER FOR NOT FOUNDSET done = 1;SELECT salary INTO employee_salaryFROM employeesWHERE employee_id = employee_id;IF done = 1 THENSELECT '未找到員工' AS message;ELSESELECT employee_salary AS Salary;END IF;
END$$DELIMITER ;

五、 事務控制

事務概述

事務是一組 SQL 語句的集合,這些語句要么全部成功執行,要么全部不執行。事務的目的是確保數據的完整性和一致性。

BEGIN、COMMIT、ROLLBACK 語句

  • BEGIN 或 START TRANSACTION:開始一個新的事務。
  • COMMIT:提交當前事務,使事務中的所有更改永久生效。
  • ROLLBACK:回滾當前事務,撤銷事務中的所有更改。
  • SAVEPOINT:設置一個保存點,可以在事務中回滾到這個點。

示例

以下是一個使用事務控制的存儲過程示例,該存儲過程更新員工的工資,并在發生錯誤時回滾事務:

DELIMITER $$CREATE PROCEDURE UpdateEmployeeSalary(IN employee_id INT, IN new_salary DECIMAL(10, 2))
BEGINDECLARE exit_handler INT DEFAULT 0;DECLARE EXIT HANDLER FOR SQLEXCEPTIONBEGINSET exit_handler = 1;END;START TRANSACTION;UPDATE employeesSET salary = new_salaryWHERE employee_id = employee_id;IF exit_handler = 1 THENROLLBACK;SELECT '更新失敗' AS message;ELSECOMMIT;SELECT '更新成功' AS message;END IF;
END$$DELIMITER ;

六、 動態 SQL

動態 SQL 概述

動態 SQL 是指在運行時生成和執行 SQL 語句的技術。

PREPARE、EXECUTE、DEALLOCATE PREPARE 語句

  • PREPARE:準備執行 SQL 語句。
  • EXECUTE:執行準備好的 SQL 語句。
  • DEALLOCATE PREPARE:釋放準備好的 SQL 語句。

示例

以下是一個使用動態 SQL 的存儲過程示例,該存儲過程根據表名動態生成和執行 SQL 語句:

DELIMITER $$CREATE PROCEDURE DynamicSQL(IN table_name VARCHAR(100))
BEGINDECLARE sql_statement VARCHAR(255);SET sql_statement = CONCAT('SELECT * FROM ', table_name);PREPARE stmt FROM sql_statement;EXECUTE stmt;DEALLOCATE PREPARE stmt;
END$$DELIMITER ;

八、 存儲過程案例:

批量數據處理示例:批量更新用戶積分

以下是一個存儲過程示例,該存儲過程根據用戶的消費金額批量更新用戶的積分:

DELIMITER $$CREATE PROCEDURE UpdateUserPoints()
BEGINDECLARE user_id INT;DECLARE consumption DECIMAL(10, 2);DECLARE done INT DEFAULT 0;DECLARE cursor_name CURSOR FORSELECT id, consumptionFROM users;DECLARE CONTINUE HANDLER FOR NOT FOUNDSET done = 1;OPEN cursor_name;my_loop: LOOPFETCH cursor_name INTO user_id, consumption;IF done = 1 THENLEAVE my_loop;END IF;UPDATE usersSET points = points + consumption * 10WHERE id = user_id;END LOOP my_loop;CLOSE cursor_name;
END$$DELIMITER ;

數據校驗示例:校驗用戶輸入數據

以下是一個存儲過程示例,該存儲過程校驗用戶輸入的用戶名和密碼是否符合要求:

DELIMITER $$CREATE PROCEDURE ValidateUser(IN username VARCHAR(100), IN password VARCHAR(100))
BEGINDECLARE valid INT DEFAULT 0;IF LENGTH(username) >= 6 AND LENGTH(password) >= 8 THENSET valid = 1;END IF;SELECT valid AS IsValid;
END$$DELIMITER ;

復雜業務邏輯封裝示例:計算訂單總金額

以下是一個存儲過程示例,該存儲過程根據訂單中的商品信息計算訂單的總金額:

DELIMITER $$CREATE PROCEDURE CalculateOrderTotal(IN order_id INT, OUT total DECIMAL(10, 2))
BEGINDECLARE item_price DECIMAL(10, 2);DECLARE item_quantity INT;DECLARE total_items INT DEFAULT 0;DECLARE total_amount DECIMAL(10, 2) DEFAULT 0.0;DECLARE cursor_name CURSOR FORSELECT price, quantityFROM order_itemsWHERE order_id = order_id;DECLARE CONTINUE HANDLER FOR NOT FOUNDSET total_items = 0;OPEN cursor_name;my_loop: LOOPFETCH cursor_name INTO item_price, item_quantity;IF total_items = 0 THENLEAVE my_loop;END IF;SET total_amount = total_amount + (item_price * item_quantity);END LOOP my_loop;CLOSE cursor_name;SET total = total_amount;
END$$DELIMITER ;

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/89407.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/89407.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/89407.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

NLP文本數據增強

文章目錄 文本數據增強同義詞替換示例Python代碼示例 隨機插入示例Python代碼示例 隨機刪除示例Python代碼示例 回譯&#xff08;Back Translation&#xff09;示例Python代碼示例 文本生成模型應用方式示例Python代碼示例 總結 文本數據增強 數據增強通過對原始數據進行變換、…

(LeetCode 每日一題) 594. 最長和諧子序列 (哈希表)

題目&#xff1a;594. 最長和諧子序列 思路&#xff1a;哈希表&#xff0c;時間復雜度0(n)。 用哈希表mp來記錄每個元素值出現的次數&#xff0c;然后枚舉所有值x&#xff0c;看其x1是否存在&#xff0c;存在的話就可以維護最長的子序列長度mx。 C版本&#xff1a; class Sol…

FreePDF:讓看英文文獻像喝水一樣簡單

前言 第一次看英文文獻&#xff0c;遇到不少看不懂的英文單詞&#xff0c;一個個查非常費勁。 后來&#xff0c;學會了使用劃詞翻譯&#xff0c;整段整段翻譯查看&#xff0c;極大提升看文獻效率。 最近&#xff0c;想到了一種更快的看文獻的方式&#xff0c;那就是把英文PD…

Scikit-learn:機器學習的「萬能工具箱」

——三行代碼構建AI模型的全棧指南** ### **一、誕生背景&#xff1a;讓機器學習從實驗室走向大眾** **2010年前的AI困境**&#xff1a; - 學術界模型難以工程化 - 算法實現碎片化&#xff08;MATLAB/C主導&#xff09; - 企業應用門檻極高 > **破局者**&#xff1a;Da…

GPT-1論文閱讀:Improving Language Understanding by Generative Pre-Training

這篇論文提出了 GPT (Generative Pre-Training) 模型&#xff0c;這是 GPT系列&#xff08;包括 GPT-2, GPT-3, ChatGPT, GPT-4 等&#xff09;的奠基之作。它標志著自然語言處理領域向大規模無監督預訓練任務特定微調范式的重大轉變&#xff0c;并取得了顯著的成功。 文章鏈接…

Hadoop大數據-Mysql的數據同步工具Maxwell安裝與使用( 詳解)

目錄 一、前置基礎知識 1、主從復制&#xff08;Replication&#xff09; 2、數據恢復 3、數據庫熱備 4、讀寫分離 5、存儲位置及命名 二、Maxwell簡介 1、簡介 2、Maxwell同步數據特點 2.1.歷史記錄同步 2.2.斷點續傳 三、前期準備 1、查看網卡&#xff1a; 2、…

分布式系統的一致性模型:核心算法與工程實踐

目錄 一、分布式一致性的核心挑戰二、主流一致性算法原理剖析1. Paxos&#xff1a;理論基礎奠基者2. Raft&#xff1a;工業級首選方案3. ZAB&#xff1a;ZooKeeper的引擎 三、算法實現與代碼實戰Paxos基礎實現&#xff08;Python偽代碼&#xff09;Raft日志復制核心邏輯 四、關…

Apache HTTP Server部署全攻略

httpd 簡介 httpd&#xff08;Apache HTTP Server&#xff09;是一款歷史悠久的開源 Web 服務器軟件&#xff0c;由 Apache 軟件基金會開發和維護。自 1995 年首次發布以來&#xff0c;Apache 一直是 Web 服務器領域的領導者&#xff0c;以其穩定性、安全性和靈活性著稱。根據…

信號處理學習——文獻精讀與code復現之TFN——嵌入時頻變換的可解釋神經網絡(下)

書接上文: 信號處理學習——文獻精讀與code復現之TFN——嵌入時頻變換的可解釋神經網絡&#xff08;上&#xff09;-CSDN博客 接下來是重要的代碼復現&#xff01;&#xff01;&#xff01;GitHub - ChenQian0618/TFN: this is the open code of paper entitled "TFN: A…

線上故障排查:簽單合同提交報錯分析-對接e簽寶

在企業管理系統中&#xff0c;合同生成與簽署環節至關重要&#xff0c;尤其是在使用第三方平臺進行電子簽署時。本文將通過實際的報錯信息&#xff0c;分析如何進行線上故障排查&#xff0c;解決合同生成過程中出現的問題。 #### 1. 錯誤描述 在嘗試生成合同并提交至電子簽署…

知攻善防靶機 Linux easy溯源

知攻善防 【護網訓練-Linux】應急響應靶場-Easy溯源 小張是個剛入門的程序猿&#xff0c;在公司開發產品的時候突然被叫去應急&#xff0c;小張心想"早知道簡歷上不寫會應急了"&#xff0c;于是call了運維小王的電話&#xff0c;小王說"你面試的時候不是說會應急…

原神八分屏角色展示頁面(純前端html,學習交流)

原神八分屏角色展示頁面 - 一個精美的前端交互項目 項目簡介 這是一個基于原神游戲角色制作的八分屏展示頁面&#xff0c;采用純前端技術實現&#xff0c;包含了豐富的動畫效果、音頻交互和視覺設計。項目展示了一些熱門原神角色&#xff0c;每個角色都有獨立的介紹頁面和專屬…

華為認證二選一:物聯網 VS 人工智能,你的賽道在哪里?

一篇不講情懷只講干貨的科普指南 一、華為物聯網 & 人工智能到底在搞什么&#xff1f; 華為物聯網&#xff08;IoT&#xff09; 的核心是 “萬物互聯”。 通過傳感器、通信技術&#xff08;如NB-IoT/5G&#xff09;、云計算平臺&#xff08;如OceanConnect&#xff09;&…

CloudLens for PolarDB:解鎖數據庫性能優化與智能運維的終極指南

隨著企業數據規模的爆炸式增長,數據庫性能管理已成為技術團隊的關鍵挑戰。本文深入探討如何利用CloudLens for PolarDB實現高級監控、智能診斷和自動化運維,幫助您構建一個自我修復、高效運行的數據庫環境。 引言:數據庫監控的演進 在云原生時代,傳統的數據庫監控方式已不…

MySQL中TINYINT/INT/BIGINT的典型應用場景及實例

以下是MySQL中TINYINT/INT/BIGINT的典型應用場景及實例說明&#xff1a; 一、TINYINT&#xff08;1字節&#xff09; 1.狀態標識 -- 用戶激活狀態&#xff08;0未激活/1已激活&#xff09; ALTER TABLE users ADD is_active TINYINT(1) DEFAULT 0; 適用于布爾值存儲和狀態碼…

YOLOv13:最新的YOLO目標檢測算法

[2506.17733] YOLOv13: Real-Time Object Detection with Hypergraph-Enhanced Adaptive Visual Perception Github: https://github.com/iMoonLab/yolov13 YOLOv13&#xff1a;利用超圖增強型自適應視覺感知進行實時物體檢測 主要的創新點提出了HyperACE機制、FullPAD范式、輕…

【深入淺出:計算流體力學(CFD)基礎與核心原理--從NS方程到工業仿真實踐】

關鍵詞&#xff1a;#CFD、#Navier-Stokes方程、#有限體積法、#湍流模型、#網格收斂性、#工業仿真驗證 一、CFD是什么&#xff1f;為何重要&#xff1f; 計算流體力學&#xff08;Computational Fluid Dynamics, CFD&#xff09; 是通過數值方法求解流體流動控制方程&#xff0…

qt常用控件--04

文章目錄 qt常用控件labelLCD NumberProgressBar結語 很高興和大家見面&#xff0c;給生活加點impetus&#xff01;&#xff01;開啟今天的編程之路&#xff01;&#xff01; 今天我們進一步c11中常見的新增表達 作者&#xff1a;?( ‘ω’ )?260 我的專欄&#xff1a;qt&am…

Redmine:一款基于Web的開源項目管理軟件

Redmine 是一款基于 Ruby on Rails 框架開發的開源、跨平臺、基于 Web 的項目管理、問題跟蹤和文檔協作軟件。 Redmine 官方網站自身就是基于它構建的一個 Web 應用。 功能特性 Redmine 的主要特點和功能包括&#xff1a; 多項目管理&#xff1a; Redmine 可以同時管理多個項…

FPGA FMC 接口

1 FMC 介紹 FMC 接口即 FPGA Mezzanine Card 接口,中文名為 FPGA 中間層板卡接口。以下是對它的詳細介紹: 標準起源:2008 年 7 月,美國國家標準協會(ANSI)批準和發布了 VITA 57 FMC 標準。該標準由從 FPGA 供應商到最終用戶的公司聯盟開發,旨在為位于基板(載卡)上的 …