MySQL must know 15 stored procedures: improve performance and security

The reading is compiled from "MySQL Must Know and Know" - Zhu Xiaofeng . For details, please log in to the purchase column on the official website of Geek Time .

background

In the supermarket project, after the end of business every day, the supermarket operator has to calculate the sales volume of the day, calculate the cost and gross profit and other business data, which means that repeated data statistics work is done every day. In fact, this kind of scenario with a large amount of data and a complex calculation process is very suitable for using stored procedures .

To put it simply, a stored procedure is to pre-store a series of SQL statements on the MySQL server. All statements are executed.

Not only is the execution efficiency very high, but the client does not need to send all SQL statements to the server through the network, which reduces the risk of SQL statements being exposed to the Internet and improves the security of data query.


create stored procedure

create procedure 存储过程名 ([in | out | inout] 参数名称 类型) 程序体

data preparation:

mysql> select * from demo.transactiondetails;
+---------------+------------+----------+------------+------------+
| transactionid | itemnumber | quantity | salesprice | salesvalue |
+---------------+------------+----------+------------+------------+
|             1 |          1 |        2 |      89.00 |     178.00 |
|             1 |          2 |        5 |       5.00 |      25.00 |
|             2 |          1 |        3 |      89.00 |     267.00 |
|             3 |          2 |       10 |       5.00 |      50.00 |
|             3 |          3 |        3 |      15.00 |      45.00 |
+---------------+------------+----------+------------+------------+
5 rows in set (0.01 sec)

mysql> select * from demo.transactionhead;
+---------------+------------------+------------+---------------------+----------+-----------+
| transactionid | transactionno    | operatorid | transdate           | memberid | cashierid |
+---------------+------------------+------------+---------------------+----------+-----------+
|             1 | 0120201201000001 |          1 | 2020-12-01 00:00:00 |        1 |         1 |
|             2 | 0120201202000001 |          2 | 2020-12-02 00:00:00 |        2 |         1 |
|             3 | 0120201202000002 |          1 | 2020-12-01 01:00:00 |     NULL |         1 |
+---------------+------------------+------------+---------------------+----------+-----------+
3 rows in set (0.00 sec)

mysql> select * from demo.goodsmaster;
+------------+---------+-----------+---------------+------+-----------+----------------+
| itemnumber | barcode | goodsname | specification | unit | saleprice | avgimportprice |
+------------+---------+-----------+---------------+------+-----------+----------------+
|          1 | 0001    || 16||     90.00 |          33.50 |
|          2 | 0002    || NULL          ||      5.00 |           3.50 |
|          3 | 0003    | 胶水      | NULL          ||     10.00 |          11.00 |
+------------+---------+-----------+---------------+------+-----------+----------------+

The stored procedure will use the data in the three tables just now to perform calculations, and store the calculated results in the single product statistics table below.

mysql> describe demo.dailystatistics;
+-------------+---------------+------+-----+---------+----------------+
| Field       | Type          | Null | Key | Default | Extra          |
+-------------+---------------+------+-----+---------+----------------+
| id          | int           | NO   | PRI | NULL    | auto_increment |
| itemnumber  | int           | YES  |     | NULL    |                |
| quantity    | decimal(10,3) | YES  |     | NULL    |                |
| actualvalue | decimal(10,2) | YES  |     | NULL    |                |
| cost        | decimal(10,2) | YES  |     | NULL    |                |
| profit      | decimal(10,2) | YES  |     | NULL    |                |
| profitratio | decimal(10,4) | YES  |     | NULL    |                |
| salesdate   | datetime      | YES  |     | NULL    |                |
+-------------+---------------+------+-----+---------+----------------+

Create a stored procedure to complete the calculation of single product sales statistics:

  1. Change the delimiter of the SQL statement to "//". Because the stored procedure contains many SQL statements, if the delimiter is not modified, MySQL will think that the statement is over and execute it when it reads the delimiter ";" of the first SQL statement, which will cause an error.
  2. Create a stored procedure that passes in the date to be processed as a parameter. At the same time, use the BEGIN and END keywords to wrap the SQL statement in the stored procedure to form the program body of the stored procedure.
  3. In the program body, first define two variables of data type DATETIME, which are used to record the start time and end time of the data to be calculated.
  4. Delete the data in the same time period in the single product statistics table that saves the result data, in order to prevent data duplication.
  5. Calculate the total sales quantity, total sales amount, total cost, gross profit and gross profit rate of a single product at the start time and the end time, and store the results in the single product statistics table.
delimiter //  -- 设置分割符为//
create procedure demo.dailyoperation(transdate text)
begin  -- 开始程序体
declare startdate, enddate datetime;  -- 定义变量
set startdate = date_format(transdate, '%Y-%m-%d');  -- 给起始时间赋值
set enddate = date_add(transdate, interval 1 day);  -- 截止时间赋值为1天以后
-- 删除原有数据
delete from demo.dailystatistics where salesdate = startdate;
-- 重新插入数据
insert into demo.dailystatistics
(
salesdate,
itemnumber,
quantity,
actualvalue,
cost,
profit,
profitratio
)
select 
left(b.transdate, 10), 
a.itemnumber, 
sum(a.quantity), 
sum(a.salesvalue), 
sum(a.quantity*c.avgimportprice),  -- 计算成本
sum(a.salesvalue-a.quantity*c.avgimportprice),  -- 计算毛利
case sum(a.salesvalue) when 0 then 0 else round(sum(a.salesvalue-a.quantity*c.avgimportprice)/sum(a.salesvalue), 4) end  -- 计算毛利率
from demo.transactiondetails as a
join demo.transactionhead as b on (a.transactionid = b.transactionid)
join demo.goodsmaster as c on (a.itemnumber = c.itemnumber)
where b.transdate > startdate and b.transdate < enddate
group by left(b.transdate, 10), a.itemnumber
order by left(b.transdate, 10), a.itemnumber;
end
//
delimiter ; -- 恢复分隔符为;

Stored procedure parameters

Stored procedures can have parameters or no parameters. Generally speaking, when we call a stored procedure through a client or an application, if we need to interact with the stored procedure, for example, the stored procedure needs to perform some kind of data processing and calculation based on the input value, or it needs to If a calculation result is returned to the client or application that calls it, parameters need to be set. Otherwise, no parameters need to be set.

There are 3 parameters, namely IN, OUT and INOUT.

  • IN represents the input parameter, and the stored procedure just reads the value of this parameter. If no parameter type is defined, the default is IN, which means input parameters.
  • OUT represents the output parameter. During the execution of the stored procedure, a calculation result value is assigned to this parameter. After the execution is completed, the client or application program that calls the stored procedure can read the value returned by the parameter.
  • INOUT indicates that this parameter can be used as both an input parameter and an output parameter.

In addition to defining the parameter type, it is also necessary to define the data type of the parameter. In this stored procedure, the data type of a parameter transition is defined as text. The purpose of this parameter is to tell the stored procedure which day's data I want to process. It is not specified whether the parameter type is IN, OUT or INOUT. This is because in MySQL, if the parameter type is not specified, the default is IN, which means an input parameter.

stored procedure body

At the beginning of the program body, two variables are defined, namely startdate and enddate. They are all datetime types, and their function is to calculate the time interval of the data to be filtered according to the input parameter translate.

The following code completes the calculation of the start time and deadline in 3 steps, and assigns them to the variables startdate and enddate respectively.

  • Use the date_format() function to convert the input parameters into date and time data in the format of MM, DD, YYYY, for example, if the input parameter is "2020-12-01", then the converted date and time value is " 2020-12-01 00:00:00", means 00:00:00 on December 1, 2020.
  • Assign the value calculated in the first step to the variable startdate as the starting time.
  • Assign the value calculated in the first step to the variable enddate through the date_add() function to calculate the time one day later.

After calculating the start time and end time, first delete the statistical data of the single product whose date needs to be calculated to prevent data duplication. Next, we recalculate the sales statistics of the single product, and insert the calculated results into the single product statistics table.

It should be noted that the case function is used here to solve the problem of calculating the gross profit when the sales amount is 0. This is to prevent calculations from reporting errors due to division by 0. Don't think that the sales amount must be greater than 0. In the process of actual project operation, the actual sales amount will be 0 due to discounts. In actual work, take these extreme situations into consideration and take precautions in advance, so that your code can be stable and reliable.


View stored procedures

show create procedure demo.dailyoperation \G
mysql> show create procedure demo.dailyoperation \G
*************************** 1. row ***************************
           Procedure: dailyoperation
            sql_mode: STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION
    Create Procedure: CREATE DEFINER=`root`@`localhost` PROCEDURE `dailyoperation`(transdate text)
begin
declare startdate, enddate datetime;
set startdate = date_format(transdate, '%Y-%m-%d');
set enddate = date_add(transdate, interval 1 day);
-- 删除原有数据
delete from demo.dailystatistics where salesdate = startdate;
-- 重新插入数据
insert into demo.dailystatistics
(
salesdate,
itemnumber,
quantity,
actualvalue,
cost,
profit,
profitratio
)
select
left(b.transdate, 10),
a.itemnumber,
sum(a.quantity),
sum(a.salesvalue),
sum(a.quantity*c.avgimportprice),
sum(a.salesvalue-a.quantity*c.avgimportprice),
case sum(a.salesvalue) when 0 then 0 else round(sum(a.salesvalue-a.quantity*c.avgimportprice)/sum(a.salesvalue), 4) end
from demo.transactiondetails as a
join demo.transactionhead as b on (a.transactionid = b.transactionid)
join demo.goodsmaster as c on (a.itemnumber = c.itemnumber)
where b.transdate > startdate and b.transdate < enddate
group by left(b.transdate, 10), a.itemnumber
order by left(b.transdate, 10), a.itemnumber;
end
character_set_client: utf8mb4
collation_connection: utf8mb4_0900_ai_ci
  Database Collation: utf8mb4_0900_ai_ci
1 row in set (0.00 sec)

call stored procedure

Call this stored procedure and pass it a parameter "2020-12-01", which is to calculate the single product statistics on December 1, 2020:

mysql> update demo.transactiondetails set quant^Chere transactionid=3 and itemnumber=3;
mysql> CALL demo.dailyoperation('2020-12-01');
Query OK, 2 rows affected (0.01 sec)

The execution result of the stored procedure prompts "Query OK", indicating that the execution is successful. "2 rows affected" indicates that the execution result has affected 2 data records.

mysql> select * from demo.dailystatistics;
+----+------------+----------+-------------+-------+--------+-------------+---------------------+
| id | itemnumber | quantity | actualvalue | cost  | profit | profitratio | salesdate           |
+----+------------+----------+-------------+-------+--------+-------------+---------------------+
|  4 |          2 |   10.000 |       50.00 | 35.00 |  15.00 |      0.3000 | 2020-12-01 00:00:00 |
|  5 |          3 |    3.000 |       45.00 | 33.00 |  12.00 |      0.2667 | 2020-12-01 00:00:00 |
+----+------------+----------+-------------+-------+--------+-------------+---------------------+
2 rows in set (0.00 sec)

It can be seen that the stored procedure is executed, it calculates the statistical results of the single product we need, and stores the statistical results in the single product statistical table.

If you do not use stored procedure statements, query all:

mysql> select  left(b.transdate, 10),  a.itemnumber,  sum(a.quantity),
    -> sum(a.salesvalue),  sum(a.quantity*c.avgimportprice) as 成本,
    -> sum(a.salesvalue-a.quantity*c.avgimportprice) as 毛利,
    -> case sum(a.salesvalue) when 0 then 0 else round(sum(a.salesvalue- a.quantity*c.avgimportprice)/sum(a.salesvalue), 4) end as 毛利率
    -> from demo.transactiondetails as a
    -> join demo.transactionhead as b on (a.transactionid = b.transactionid)
    -> join demo.goodsmaster as c on (a.itemnumber = c.itemnumber)
    -> group by left(b.transdate, 10), a.itemnumber
    -> order by left(b.transdate, 10), a.itemnumber;
+-----------------------+------------+-----------------+-------------------+--------+--------+--------+
| left(b.transdate, 10) | itemnumber | sum(a.quantity) | sum(a.salesvalue) | 成本   | 毛利   | 毛利率 |
+-----------------------+------------+-----------------+-------------------+--------+--------+--------+
| 2020-12-01            |          1 |               2 |            178.00 |  67.00 | 111.00 | 0.6236 |
| 2020-12-01            |          2 |              15 |             75.00 |  52.50 |  22.50 | 0.3000 |
| 2020-12-01            |          3 |               3 |             45.00 |  33.00 |  12.00 | 0.2667 |
| 2020-12-02            |          1 |               3 |            267.00 | 100.50 | 166.50 | 0.6236 |
+-----------------------+------------+-----------------+-------------------+--------+--------+--------+
4 rows in set (0.01 sec)

modify stored procedure

To modify the content of the stored procedure, it is recommended to operate in Workbench. This is because the stored procedure can be directly modified in it, and if the stored procedure is modified with SQL commands, the stored procedure must be deleted and recreated. In contrast, it is relatively simple to modify in the Workbench.

In the navigation bar on the left, find the database demo. After expanding it, find the stored procedure, and then find the daily operation you just created. Click the design button on the right to modify it in the work area on the right. After the modification is complete, click the button "Apply" at the bottom right of the workspace to save the modification.

Please add a picture description

In MySQL, stored procedures do not have a dedicated integrated development environment like ordinary programming languages ​​(such as VC++, Java, etc.). Therefore, you can use the SELECT statement to query the intermediate results of program execution to debug the correctness of a SQL statement. After the debugging is successful, move the SELECT statement to the next SQL statement, and then debug the next SQL statement. In this way, step by step, you can complete the debugging of all operations in the stored procedure. Of course, you can also copy the SQL statement in the stored procedure and debug it segment by segment.


delete stored procedure

drop procedure 存储过程名称;

summary

The advantages of stored procedures are high execution efficiency and safety. However, it also has its own disadvantages, that is, the cost of development and debugging is relatively high, and it is not easy to maintain.

In the process of developing stored procedures, although there are some third-party tools that can debug stored procedures, there is a charge. It is recommended to debug by outputting variable values ​​through SELECT statements. Although it is a bit cumbersome, it is low-cost, simple and reliable. If stored procedures need to be distributed with the product, consider placing scripts in the installer to create the required stored procedures during product installation.

Test question: To write a simple stored procedure, the requirement is to define 2 parameters, one input parameter a, the data type is INT; the other output parameter is b, the type is INT. The operation completed by the program body is: b = a + 1

delimiter //
create procedure demo.test_add(in a int, out b int)
begin
set b = a + 1;
end
//
delimiter ;
-- 调用方法
mysql> call demo.test_add(1, @a);
Query OK, 0 rows affected (0.02 sec)

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

Guess you like

Origin blog.csdn.net/qq_31362767/article/details/124511184