Hướng dẫn viết store procedure trong sql server năm 2024

Hãy nâng cấp lên Microsoft Edge để tận dụng các tính năng mới nhất, bản cập nhật bảo mật và hỗ trợ kỹ thuật.

Create a stored procedure

  • Bài viết
  • 07/18/2023

Trong bài viết này

Applies to:

This article describes how to create a Transact-SQL stored procedure by using SQL Server Management Studio and by using the Transact-SQL CREATE PROCEDURE statement.

Permissions

Requires CREATE PROCEDURE permission in the database and ALTER permission on the schema in which the procedure is being created.

How to create a stored procedure

You can use one of the following:

Use SQL Server Management Studio

To create a procedure in Object Explorer

  1. In Object Explorer, connect to an instance of Database Engine and then expand that instance.
  2. Expand Databases, expand the AdventureWorks2022 database, and then expand Programmability.
  3. Right-click Stored Procedures, and then select New Stored Procedure.
  4. On the Query menu, select Specify Values for Template Parameters.
  5. In the Specify Values for Template Parameters dialog box, enter the following values for the parameters shown. Parameter Value Author Your name Create Date Today's date Description Returns employee data. Procedure_name HumanResources.uspGetEmployeesTest @Param1 @LastName @Datatype_For_Param1 nvarchar(50) Default_Value_For_Param1 NULL @Param2 @FirstName @Datatype_For_Param2 nvarchar(50) Default_Value_For_Param2 NULL
  6. Select OK.
  7. In the Query Editor, replace the SELECT statement with the following statement: SELECT FirstName, LastName, Department FROM HumanResources.vEmployeeDepartmentHistory WHERE FirstName = @FirstName AND LastName = @LastName
    AND EndDate IS NULL;  
    
  8. To test the syntax, on the Query menu, select Parse. If an error message is returned, compare the statements with the previous information and correct as needed.
  9. To create the procedure, from the Query menu, select Execute. The procedure is created as an object in the database.
  10. To see the procedure listed in Object Explorer, right-click Stored Procedures and select Refresh.
  11. To run the procedure, in Object Explorer, right-click the stored procedure name HumanResources.uspGetEmployeesTest and select Execute Stored Procedure.
  12. In the Execute Procedure window, enter Margheim as the value for the parameter @LastName and enter the value Diane as the value for the parameter @FirstName.

Warning

Validate all user input. Do not concatenate user input before you validate it. Never execute a command constructed from unvalidated user input.

Use Transact-SQL

To create a procedure in Query Editor

  1. In Object Explorer, connect to an instance of Database Engine.
  2. From the File menu, select New Query.
  3. Copy and paste the following example into the query window and select Execute. This example creates the same stored procedure as in the previous example, but using a different procedure name.

    USE AdventureWorks2022; GO CREATE PROCEDURE HumanResources.uspGetEmployeesTest2

    @LastName nvarchar(50),  
    @FirstName nvarchar(50)  
    
    AS
    SET NOCOUNT ON;  
    SELECT FirstName, LastName, Department  
    FROM HumanResources.vEmployeeDepartmentHistory  
    WHERE FirstName = @FirstName AND LastName = @LastName  
    AND EndDate IS NULL;  
    
    GO

To run the procedure, copy and paste the following example into a new query window and select Execute. Notice that different methods of specifying the parameter values are shown.

(Những ví dụ trong bài viết dựa trên cơ sở dữ liệu sakila - https://dev.mysql.com/doc/sakila/en/sakila-installation.html)

Stored procedure (Thủ tục)

Stored procedure là cái gì?

  • Là đoạn chương trình kịch bản (programming scripts) với các câu lệnh SQL nhúng (embedded SQL) được lưu dưới dạng đã được biên dịch và thi hành thực tiếp bởi MySQL server,
  • SP cho phép lưu trữ các logic ứng dụng trên CSDL. Khi gọi SP lần đầu tiên, MySQL sẽ tạo một lịch thực thi và lưu trữ nó trong bộ nhớ đệm. Ở những lần gọi hàm tiếp theo, MySQL sử dụng sử dựng lại lịch thực thi được lưu rất nhanh với hiệu xuất đáng tin cậy.
  • SP là một mã SQL đã chuẩn bị sẵn mà bạn có thể lưu, do đó đoạn mã có thể được sử dụng lại nhiều lần.
  • Vì vậy, nếu bạn có một truy vấn SQL mà bạn viết đi viết lại nhiều lần, hãy lưu nó dưới dạng một thủ tục được lưu trữ, sau đó chỉ cần gọi nó để thực thi nó.
  • Cũng có thể chuyển các tham số cho một thủ tục được lưu trữ, để thủ tục được lưu trữ có thể hoạt động dựa trên (các) giá trị tham số được truyền vào.

Vì sao nên dùng Stored procedure

  • Giảm dư thừa mã chương trình: Các đoạn mã tương tự trong các ứng dụng như thêm, cập nhật có thể lưu ở phía CSDL
  • Cải thiện tốc độ thực thi câu lệnh SSQL
  • Bảo trì: Nếu có sự thay đổi trong CSDL, mã lệnh cần thay đổi có thể xác định trong các SP
  • An ninh CSDL tốt hơn: Trong các ứng dụng an ninh cao, với SP có thể kiểm soát truy cập dữ liệu và đưa ra các qui định an ninh tập trung.

Nhược điểm của Stored procedure

  • Thiếu tính khả chuyển (Lack of Portability)
    • SP khó chuyển từ một DBMS sang một DBMS khác. Yêu cầu lập trình và kiểm thử lại đáng kể
      • SQLServer: T-SQL
      • Oracle: PL-SQL
  • Tải DB Server
    • Sử dụng SP nhiều có thể gây quá tải MySQL server (SQL Server phải lưu trữ quá nhiều kế hoạc thực thi)
  • Hạn chế ngôn ngữ lập trình
    • Lập trình SP không phong phú như các nền tảng phát triển khác như Java hay PHP
    • Lưu ý: Các phiên bản tương lai của MySQL có thể cung cấp các giao diện cho phép tạo các SP sử dụng các ngôn ngữ bên ngoài, ví dụ Java

Sử dụng Stored Procedure khi?

  • Thực hiện những phép toán phức tạp, lặp lại nhiều lần
  • Project đòi hỏi nghiêm ngặt về tốc độ thực thi . Stored Procedure cho tốc độ thực thi nhanh hơn so với các câu lệnh SQL Server thông thường vì Stored Procedure đã được lưu sẵn tại SQL server, do vậy nó chỉ cần gọi một dòng lệnh để thực thi Stored Procedure, điều này giúp tăng tốc độ thực thi.
  • Trong quá trình tạo Stored Procedure, SQL Server đã tối ưu hóa những dòng lệnh này, điều này giúp cho tốc độ thực thi cao hơn câu lệnh SQL thông thường rất nhiều.

Không cần sử dụng Stored Procedure khi?

  • Store Procedured làm quá trình debug trở nên khó khăn hơn.

Vì vậy hãy nghĩ đến Stored Procedure như là phương án cuối cùng để tối ưu hóa tốc độ thực thi chương trình. Các project có size nhỏ và vừa nên ưu tiên sử dụng các thư viện ORM (Object Relation Mapping), như Entity Framework cho C#, TypeORM cho NodeJs.

Sự khác nhau của Thủ tục, Hàm

Thủ tục (PROCEDURE) Hàm (FUNCTION) Cách gọi CALL Sử dụng các câu lệnh trong sql như SELECT, UPDATE Giá trị trả về Có thể một hoặc nhiều kết quả SELECT và các tham số out Trả về một giá trị duy nhất thông qua RETURN Các tham số Giá trị (input) và tham chiếu (output) Các tham số (IN, OUT, INOUT) Chỉ các giá trị tham số vào (input). Không cần các thẻ như IN.. Gọi thủ tục/hàm Có thể gọi các thủ tục và hàm khác Chỉ có thể gọi các hàm khác

Cú pháp tạo Thủ tục/Hàm

CREATE PROCEDURE actorList(IN max_id INT)
AS
BEGIN
    SELECT 
        first_name, 
        last_price
    FROM 
        actor
    WHERE
        actor_id < max_id
    ORDER BY 
        first_name;
END;

8

CREATE PROCEDURE actorList(IN max_id INT)
AS
BEGIN
    SELECT 
        first_name, 
        last_price
    FROM 
        actor
    WHERE
        actor_id < max_id
    ORDER BY 
        first_name;
END;

9

Ví dụ

Tạo một thủ tục tên uspActorList trả về danh sách first_name, last_name của các actor sắp xếp theo first_name

CREATE PROCEDURE uspActorList
AS
BEGIN
    SELECT 
        first_name, 
        last_price
    FROM 
        actor
    ORDER BY 
        first_name;
END;

Tạo một thủ tục tên uspActorList có tham số đầu vào là max_id trả về danh sách first_name, last_name của các actor sắp xếp theo first_name và có id < max_id

CREATE PROCEDURE actorList(IN max_id INT)
AS
BEGIN
    SELECT 
        first_name, 
        last_price
    FROM 
        actor
    WHERE
        actor_id < max_id
    ORDER BY 
        first_name;
END;

Tạo một function tên film_in_stock trả về số lượng với đầu vào (IN) là p_film_id, p_store_id, đầu ra (OUT) là p_film_count


CREATE PROCEDURE film_in_stock(IN p_film_id INT, IN p_store_id INT, OUT p_film_count INT)
READS SQL DATA
BEGIN
     SELECT inventory_id
     FROM inventory
     WHERE film_id = p_film_id
     AND store_id = p_store_id
     AND inventory_in_stock(inventory_id);
     SELECT FOUND_ROWS() INTO p_film_count;
END $$

Các câu lệnh khác

DELIMITER $$

  • Thường được sử dụng khi xác định các hàm, thủ tục và trình kích hoạt (trong đó bạn phải sử dụng nhiều câu lệnh). Dấu

    CREATE PROCEDURE film_in_stock(IN p_film_id INT, IN p_store_id INT, OUT p_film_count INT) READS SQL DATA BEGIN

        SELECT inventory_id  
        FROM inventory  
        WHERE film_id = p_film_id  
        AND store_id = p_store_id  
        AND inventory_in_stock(inventory_id);  
        SELECT FOUND_ROWS() INTO p_film_count;  
    
    END $$

    0 được sử dụng để xác định phần đầu của toàn bộ thủ tục, bên trong các câu lệnh riêng lẻ được kết thúc bởi

    CREATE PROCEDURE film_in_stock(IN p_film_id INT, IN p_store_id INT, OUT p_film_count INT) READS SQL DATA BEGIN

        SELECT inventory_id  
        FROM inventory  
        WHERE film_id = p_film_id  
        AND store_id = p_store_id  
        AND inventory_in_stock(inventory_id);  
        SELECT FOUND_ROWS() INTO p_film_count;  
    
    END $$

    1. Bằng cách đó, khi mã được chạy trong máy khách mysql, máy khách có thể cho biết nơi toàn bộ thủ tục kết thúc và thực thi nó như một đơn vị thay vì thực thi các câu lệnh riêng lẻ bên trong.
  • Lưu ý rằng từ khóa DELIMITER chỉ là một chức năng của command line mysql client (và một số máy khách khác) và không phải là một cấu trúc của SQL thông thường. Nó sẽ không hoạt động nếu chuyển nó qua một API ngôn ngữ lập trình đến MySQL. Một số ứng dụng khách khác như PHPMyAdmin có các phương thức khác để chỉ định dấu phân cách không mặc định.

Gán giá trị cho biến

Sử dụng SET hoặc SELECT INTO.

VD:


CREATE PROCEDURE film_in_stock(IN p_film_id INT, IN p_store_id INT, OUT p_film_count INT)
READS SQL DATA
BEGIN
     SELECT inventory_id
     FROM inventory
     WHERE film_id = p_film_id
     AND store_id = p_store_id
     AND inventory_in_stock(inventory_id);
     SELECT FOUND_ROWS() INTO p_film_count;
END $$

2

Gọi thủ tục:


CREATE PROCEDURE film_in_stock(IN p_film_id INT, IN p_store_id INT, OUT p_film_count INT)
READS SQL DATA
BEGIN
     SELECT inventory_id
     FROM inventory
     WHERE film_id = p_film_id
     AND store_id = p_store_id
     AND inventory_in_stock(inventory_id);
     SELECT FOUND_ROWS() INTO p_film_count;
END $$

3


CREATE PROCEDURE film_in_stock(IN p_film_id INT, IN p_store_id INT, OUT p_film_count INT)
READS SQL DATA
BEGIN
     SELECT inventory_id
     FROM inventory
     WHERE film_id = p_film_id
     AND store_id = p_store_id
     AND inventory_in_stock(inventory_id);
     SELECT FOUND_ROWS() INTO p_film_count;
END $$

4

Mệnh đề IF THEN

IF condition THEN 
commands; 
[ELSEIF condition THEN 
commands;] 
[ELSEcommands;] 
END IF; 

Mệnh đề CASE

CASE expression 
WHEN value1 THEN commands; 
[WHEN value2 THEN commands;] 
[ELSE commands;] 
END CASE; 

Mệnh đề REPEAT UNTIL

[loopname:] 
REPEAT commands; 
UNTIL condition 
END REPEAT [loopname]; 

Mệnh đề WHILE

[loopname:] 
WHILE condition DO commands;
 END WHILE [loopname];

Mệnh đề LEAVE

  • LEAVE dùng thoát khỏi vòng lặp
  • LEAVE cũng có thể dùng để thoát khỏi BEGIN-END

Tương tự như mệnh đề BREAK trong các ngôn ngữ lập trình khác

Xử lý lỗi thông qua Handlers

  • Luôn có khả năng Store Procedure gặp lỗi trong khi thực thi các lệnh SQL. MySQL cung cấp kỹ thuật xử lý lỗi thông qua Handler
  • Một handler cần định nghĩa sau khai báo các biến, con trỏ và điều kiện, nhưng trước các lệnh SQL
  • Cú pháp khai báo một Handler
                             `DECLARE type HANDLER FOR condition1, condition2, condition3, ... statement;   
    
    `
    • type: CONTINUE hoặc EXIT
    • condition(s): Các điều kiện mà handler sẽ được gọi (VD: Not found, SqlException,..)
    • statement: Câu lệnh sẽ thi hành khi có điều kiện xảy ra

VD: Nếu không tim thấy (NOT FOUND) customer_id là khách hàng chưa trả đĩa thuê có id được lưu trong kho là p_inventory_id thì sẽ trả về NULL

CREATE FUNCTION inventory_held_by_customer(p_inventory_id INT) RETURNS INT
READS SQL DATA
BEGIN
  DECLARE v_customer_id INT;
  DECLARE EXIT HANDLER FOR NOT FOUND RETURN NULL;
  SELECT customer_id INTO v_customer_id
  FROM rental
  WHERE return_date IS NULL
  AND inventory_id = p_inventory_id;
  RETURN v_customer_id;
END $$

Quản lý store procedure

  • Hiển thị tất cả những Stored procedure đang tồn tại trong tất cả các cơ sở dữ liệu

    CREATE PROCEDURE film_in_stock(IN p_film_id INT, IN p_store_id INT, OUT p_film_count INT) READS SQL DATA BEGIN

        SELECT inventory_id  
        FROM inventory  
        WHERE film_id = p_film_id  
        AND store_id = p_store_id  
        AND inventory_in_stock(inventory_id);  
        SELECT FOUND_ROWS() INTO p_film_count;  
    
    END $$

    5
  • Hiển thị tất cả những Function đang tồn tại trong tất cả các cơ sở dữ liệu

    CREATE PROCEDURE film_in_stock(IN p_film_id INT, IN p_store_id INT, OUT p_film_count INT) READS SQL DATA BEGIN

        SELECT inventory_id  
        FROM inventory  
        WHERE film_id = p_film_id  
        AND store_id = p_store_id  
        AND inventory_in_stock(inventory_id);  
        SELECT FOUND_ROWS() INTO p_film_count;  
    
    END $$

    6
  • Nếu chỉ muốn hiển thị ra stored procedure của một cơ sở dữ liệu cụ thể sử dụng câu lệnh:

    CREATE PROCEDURE film_in_stock(IN p_film_id INT, IN p_store_id INT, OUT p_film_count INT) READS SQL DATA BEGIN

        SELECT inventory_id  
        FROM inventory  
        WHERE film_id = p_film_id  
        AND store_id = p_store_id  
        AND inventory_in_stock(inventory_id);  
        SELECT FOUND_ROWS() INTO p_film_count;  
    
    END $$

    7
  • Tương tự với functions:

    CREATE PROCEDURE film_in_stock(IN p_film_id INT, IN p_store_id INT, OUT p_film_count INT) READS SQL DATA BEGIN

        SELECT inventory_id  
        FROM inventory  
        WHERE film_id = p_film_id  
        AND store_id = p_store_id  
        AND inventory_in_stock(inventory_id);  
        SELECT FOUND_ROWS() INTO p_film_count;  
    
    END $$

    8

    CREATE PROCEDURE film_in_stock(IN p_film_id INT, IN p_store_id INT, OUT p_film_count INT) READS SQL DATA BEGIN

        SELECT inventory_id  
        FROM inventory  
        WHERE film_id = p_film_id  
        AND store_id = p_store_id  
        AND inventory_in_stock(inventory_id);  
        SELECT FOUND_ROWS() INTO p_film_count;  
    
    END $$

    9

    IF condition THEN commands; [ELSEIF condition THEN commands;] [ELSEcommands;] END IF;

    0
  • Hiển thị thông tin cụ thể của một procedure

    IF condition THEN commands; [ELSEIF condition THEN commands;] [ELSEcommands;] END IF;

    1

Ví dụ

  1. Tạo một stored procedure tên là displayFilmInfo nhận category_id và language_id như là các tham số:
  2. Nếu category_id và language_id được chỉ rõ, trả lại thông tin các film có category_id và language bằng các giá trị truyền vào.
  3. Nếu 0 được truyền như một tham số cho language_id thì trả lại thông tin các film có category_id là tham số truyền vào.
  4. Nếu 0 được truyền như một tham số cho category_id thì trả lại các film có language_id là tham số truyền vào.

DELIMITER $$
DROP PROCEDURE IF EXISTS displayFilmInfo;
CREATE PROCEDURE displayFilmInfo(IN p_category_id INT, IN p_language_id INT)
BEGIN
    IF(p_language_id = 0) THEN
        SELECT film.film_id FROM film
        JOIN film_category ON film.film_id = film_category.film_id AND film_category.category_id = p_category_id;
    ELSEIF (p_category_id = 0) THEN
        SELECT film.film_id FROM film
        WHERE film.language_id = p_language_id;
    ELSEIF (p_language_id > 0 AND p_category_id > 0) THEN
        SELECT film.film_id FROM film
        JOIN film_category ON film.film_id = film_category.film_id AND film_category.category_id = p_category_id
        WHERE film.language_id = p_language_id;
    END IF;
END $$
DELIMITER ;
# thực thi procedure
CALL displayFilmInfo(1,1);

Kết quả

CREATE PROCEDURE actorList(IN max_id INT)
AS
BEGIN
    SELECT 
        first_name, 
        last_price
    FROM 
        actor
    WHERE
        actor_id < max_id
    ORDER BY 
        first_name;
END;

0

  1. Viết hàm tính tổng số đĩa film được thuê của của hàng trong tháng, năm. Với tham số đầu vào là mã của hàng, tháng, năm. Sau đó sử dụng hàm trong lệnh SELECT đưa ra các cửa hàng và tổng số film được thuê tại cửa hàng trong tháng 2/2006.
  2. Procedure

CREATE PROCEDURE actorList(IN max_id INT)
AS
BEGIN
    SELECT 
        first_name, 
        last_price
    FROM 
        actor
    WHERE
        actor_id < max_id
    ORDER BY 
        first_name;
END;

1

Kết quả

CREATE PROCEDURE actorList(IN max_id INT)
AS
BEGIN
    SELECT 
        first_name, 
        last_price
    FROM 
        actor
    WHERE
        actor_id < max_id
    ORDER BY 
        first_name;
END;

2

  • Function:

CREATE PROCEDURE actorList(IN max_id INT)
AS
BEGIN
    SELECT 
        first_name, 
        last_price
    FROM 
        actor
    WHERE
        actor_id < max_id
    ORDER BY 
        first_name;
END;

3

Kết quả

CREATE PROCEDURE actorList(IN max_id INT)
AS
BEGIN
    SELECT 
        first_name, 
        last_price
    FROM 
        actor
    WHERE
        actor_id < max_id
    ORDER BY 
        first_name;
END;

4

Trigger (Hàm)

Trigger là cái gì?

  • Triggers là quá trình tự động thi hành các lệnhSQL hoặc SP sau hoặc trước các lệnh INSERT, UPDATE, hoặc DELETE.
  • Các ứng dụng có thể bao gồm: lưu lại thay đổi hoặc cập nhật dữ liệu các bảng khác.
  • Trigger chạy sau mỗi câu lệnh cập nhật bảng do đó có thể thêm tải với CSDL

Cú pháp

CREATE PROCEDURE actorList(IN max_id INT)
AS
BEGIN
    SELECT 
        first_name, 
        last_price
    FROM 
        actor
    WHERE
        actor_id < max_id
    ORDER BY 
        first_name;
END;

5

Cú pháp lệnh bên trong tương tự SP

Trong trigger, mã lệnh có thể truy cập các cột của bản ghi hiện tại

  • OLD.columnname trả lại nội dung của bản ghi trước khi bị thay đổi hoặc xóa (UPDATE, DELETE)
  • NEW.columnname trả lại nội dung của bản ghi mới hoặc bản ghi thay thế (INSERT, UPDATE)

Ví dụ

CREATE PROCEDURE actorList(IN max_id INT)
AS
BEGIN
    SELECT 
        first_name, 
        last_price
    FROM 
        actor
    WHERE
        actor_id < max_id
    ORDER BY 
        first_name;
END;

6

Tạo trigger trên bảng payment, mỗi khi thêm, sửa bảng payment sẽ cập nhật thông tin đó cùng với thông tin là thời gian thêm, sửa vào bảng payment_log (tạo thêm)

CREATE PROCEDURE actorList(IN max_id INT)
AS
BEGIN
    SELECT 
        first_name, 
        last_price
    FROM 
        actor
    WHERE
        actor_id < max_id
    ORDER BY 
        first_name;
END;

7

Quản lý trigger

  1. Trigger được lưu trữ

Trigger is stored as plain text file in the database folder as follows: /data_folder/database_name/table_name.trg,