MySQL Stored Procedure Beispiel

Wer sich mit dem SQL-Skript aus dem [post id=2634]MySQL Cursor Beispiel[/post] beschäftigt hat wird festgestellt haben, dass der dort definierte Trigger check_amount nur funktioniert, wenn nicht mehr Produkte bestellt werden, als insgesamt überhaupt in allen Geschäften (engl. stores) verfügbar sind. Im Beispiel-Skript gibt es insgesamt 550 Fernseher:

1
2
3
4
-- Insert some products
INSERT INTO products(prod_id,name,store,stock) VALUES (NULL,'Fernseher','Berlin',250)$
INSERT INTO products(prod_id,name,store,stock) VALUES (NULL,'Fernseher','Potsdam',200)$
INSERT INTO products(prod_id,name,store,stock) VALUES (NULL,'Fernseher','Bremen',100)$

Wird nun die folgende Anfrage gestellt, dann werden mehr als 550 Fernseher bestellt und es kommt zu einem Trigger-Fehler:

1
INSERT INTO orders(user_id,product,amount) VALUES (1,'Fernseher',1300)$

Um diesen Fehler zu beseitigen, habe ich den check_amount-Trigger erweitert, so dass eine Stored Procedure namens availableQuantity abgefragt wird, welche dann Auskunft darüber liefert, wie hoch die verfügbare Anzahl eines Produktes ist. Ist diese Anzahl kleiner als die bestellte Menge, dann wird die bestellte Menge einfach auf die maximal verfügbare Anzahl gesetzt.

SQL-Skript

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
-- Settings
DELIMITER $
 
-- Create database
DROP DATABASE IF EXISTS testdb_trigger$
CREATE DATABASE testdb_trigger DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci$
USE testdb_trigger$
 
-- Create tables
CREATE TABLE IF NOT EXISTS users 
(
	user_id		INT(10)			  NOT NULL AUTO_INCREMENT
	,surname	VARCHAR(255)	NOT NULL
	,prename	VARCHAR(255)	NOT NULL
	,PRIMARY KEY(user_id)	
) ENGINE = InnoDB CHARACTER SET utf8 COLLATE utf8_general_ci$
 
CREATE TABLE IF NOT EXISTS users_a_m 
(
	id        INT(10)			  NOT NULL AUTO_INCREMENT
	,user_id  INT(10)       NOT NULL
	,surname  VARCHAR(255)  NOT NULL
	,prename  VARCHAR(255)  NOT NULL
	,PRIMARY KEY(id)
	,FOREIGN KEY(user_id) REFERENCES users(user_id) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE = InnoDB CHARACTER SET utf8 COLLATE utf8_general_ci$
 
CREATE TABLE IF NOT EXISTS users_n_z 
(
	id			INT(10)			    NOT NULL AUTO_INCREMENT
	,user_id	INT(10)			  NOT NULL
	,surname	VARCHAR(255)  NOT NULL
	,prename	VARCHAR(255)  NOT NULL
	,PRIMARY KEY(id)
	,FOREIGN KEY(user_id) REFERENCES users(user_id) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE = InnoDB CHARACTER SET utf8 COLLATE utf8_general_ci$
 
CREATE TABLE IF NOT EXISTS products
(
	prod_id   INT(10)			  NOT NULL AUTO_INCREMENT
	,name     VARCHAR(255)	NOT NULL
	,store    VARCHAR(255)  NOT NULL
	,stock    INT(5)			  NOT NULL
	,PRIMARY KEY(prod_id)
) ENGINE = InnoDB CHARACTER SET utf8 COLLATE utf8_general_ci$
 
CREATE TABLE IF NOT EXISTS orders
(	
	id			INT(10)         NOT NULL AUTO_INCREMENT
	,user_id	INT(10)       NOT NULL
	,product	VARCHAR(255)  NOT NULL
	,amount		INT(5)        NOT NULL
	,PRIMARY KEY(id)
	,FOREIGN KEY(user_id) REFERENCES users(user_id) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE = InnoDB CHARACTER SET utf8 COLLATE utf8_general_ci$
 
-- Create Triggers
CREATE TRIGGER split_users AFTER INSERT
ON users FOR EACH ROW
BEGIN
	IF(NEW.surname BETWEEN 'A' AND 'N')
	THEN
		INSERT INTO users_a_m VALUES (NULL, NEW.user_id, NEW.surname, NEW.prename);
	ELSE
		INSERT INTO users_n_z VALUES (NULL, NEW.user_id, NEW.surname, NEW.prename);
	END IF;
END$
 
-- Stored procedure
CREATE PROCEDURE availableQuantity(IN product VARCHAR(255), OUT total INT(5))
BEGIN
  SELECT SUM(stock) INTO total FROM products WHERE name = product;
END$
 
-- Trigger with Cursor
CREATE TRIGGER check_amount BEFORE INSERT
ON orders FOR EACH ROW
BEGIN
	DECLARE product_id INT(10);
	DECLARE order_quantity INT(5);
	DECLARE available_quantity INT(5);
  DECLARE total_quantity INT(5);
 
	-- Cursor
	DECLARE amount_cursor CURSOR
		FOR	SELECT prod_id, stock FROM products WHERE name=NEW.product ORDER BY stock DESC;
	OPEN amount_cursor;
		SET order_quantity = NEW.amount;
 
    -- Call stored procedure
    CALL availableQuantity(NEW.product, @total);    
    SET total_quantity = (SELECT @total);
    IF(order_quantity > total_quantity)    
    THEN
      SET NEW.amount = total_quantity;
      SET order_quantity = total_quantity;
    END IF;
 
    -- Continue...
		WHILE (order_quantity > 0) 
		DO
			FETCH amount_cursor INTO product_id, available_quantity;
				IF(order_quantity > available_quantity)
				THEN
					UPDATE products
					SET stock = 0
					WHERE prod_id = product_id;
				ELSE
					UPDATE products
					SET stock = stock - order_quantity
					WHERE prod_id = product_id;					
				END IF;	
			SET order_quantity = order_quantity - available_quantity;
		END WHILE;
	CLOSE amount_cursor;
END$
 
-- Insert 10 people
INSERT INTO users(user_id,surname,prename) VALUES (NULL,'Quander','Nadja')$
INSERT INTO users(user_id,surname,prename) VALUES (NULL,'Labuhn','Milan')$
INSERT INTO users(user_id,surname,prename) VALUES (NULL,'Ebisch','Alena')$
INSERT INTO users(user_id,surname,prename) VALUES (NULL,'Paffenholz','Ellen')$
INSERT INTO users(user_id,surname,prename) VALUES (NULL,'Haas','Vin')$
INSERT INTO users(user_id,surname,prename) VALUES (NULL,'Jaber','Chris')$
INSERT INTO users(user_id,surname,prename) VALUES (NULL,'Radicke','Yannik')$
INSERT INTO users(user_id,surname,prename) VALUES (NULL,'Abadre','Sean')$
INSERT INTO users(user_id,surname,prename) VALUES (NULL,'Nähr','Friedrich')$
INSERT INTO users(user_id,surname,prename) VALUES (NULL,'Waagner','Lilian')$
 
-- Insert some products
INSERT INTO products(prod_id,name,store,stock) VALUES (NULL,'Fernseher','Berlin',250)$
INSERT INTO products(prod_id,name,store,stock) VALUES (NULL,'Fernseher','Potsdam',200)$
INSERT INTO products(prod_id,name,store,stock) VALUES (NULL,'Fernseher','Bremen',100)$
INSERT INTO products(prod_id,name,store,stock) VALUES (NULL,'Radio','Berlin',100)$
 
-- Insert some orders
INSERT INTO orders(user_id,product,amount) VALUES (1,'Fernseher',1300)$

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

Diese Website verwendet Akismet, um Spam zu reduzieren. Erfahre mehr darüber, wie deine Kommentardaten verarbeitet werden.