1drop database if exists demo;
2create database demo;
3use demo;
4create table ab_physical_person (
5person_id integer,
6first_name VARCHAR(50),
7middle_initial CHAR,
8last_name VARCHAR(50),
9primary key (person_id));
10create table ab_moral_person (
11company_id integer,
12name VARCHAR(100),
13primary key (company_id));
14create table in_inventory (
15item_id integer,
16descr VARCHAR(50),
17stock integer,
18primary key (item_id));
19create table po_order (
20po_id integer auto_increment,
21cust_type char, /* arc relationship, see cust_id */
22cust_id integer, /* FK to ab_physical_person *OR* ab_moral_person */
23primary key (po_id));
24create table po_order_line (
25po_id integer, /* FK to po_order.po_id */
26line_no integer,
27item_id integer, /* FK to in_inventory.item_id */
28qty integer);
29#
30# Schema integrity enforcement
31#
32create procedure check_pk_person(in person_type char, in id integer)
33begin
34declare x integer;
35declare msg varchar(128);
36/*
37Test integrity constraints for an 'arc' relationship.
38Based on 'person_type', 'id' points to either a
39physical person, or a moral person.
40*/
41case person_type
42when 'P' then
43begin
44select count(person_id) from ab_physical_person
45where ab_physical_person.person_id = id
46into x;
47if (x != 1)
48then
49set msg= concat('No such physical person, PK:', id);
50SIGNAL SQLSTATE '45000' SET
51MESSAGE_TEXT = msg,
52MYSQL_ERRNO = 10000;
53end if;
54end;
55when 'M' then
56begin
57select count(company_id) from ab_moral_person
58where ab_moral_person.company_id = id
59into x;
60if (x != 1)
61then
62set msg= concat('No such moral person, PK:', id);
63SIGNAL SQLSTATE '45000' SET
64MESSAGE_TEXT = msg,
65MYSQL_ERRNO = 10000;
66end if;
67end;
68else
69begin
70set msg= concat('No such person type:', person_type);
71SIGNAL SQLSTATE '45000' SET
72MESSAGE_TEXT = msg,
73MYSQL_ERRNO = 20000;
74end;
75end case;
76end
77$$
78create procedure check_pk_inventory(in id integer)
79begin
80declare x integer;
81declare msg varchar(128);
82select count(item_id) from in_inventory
83where in_inventory.item_id = id
84into x;
85if (x != 1)
86then
87set msg= concat('Failed integrity constraint, table in_inventory, PK:',
88id);
89SIGNAL SQLSTATE '45000' SET
90MESSAGE_TEXT = msg,
91MYSQL_ERRNO = 10000;
92end if;
93end
94$$
95create procedure check_pk_order(in id integer)
96begin
97declare x integer;
98declare msg varchar(128);
99select count(po_id) from po_order
100where po_order.po_id = id
101into x;
102if (x != 1)
103then
104set msg= concat('Failed integrity constraint, table po_order, PK:', id);
105SIGNAL SQLSTATE '45000' SET
106MESSAGE_TEXT = msg,
107MYSQL_ERRNO = 10000;
108end if;
109end
110$$
111create trigger po_order_bi before insert on po_order
112for each row
113begin
114call check_pk_person(NEW.cust_type, NEW.cust_id);
115end
116$$
117create trigger po_order_bu before update on po_order
118for each row
119begin
120call check_pk_person(NEW.cust_type, NEW.cust_id);
121end
122$$
123create trigger po_order_line_bi before insert on po_order_line
124for each row
125begin
126call check_pk_order(NEW.po_id);
127call check_pk_inventory(NEW.item_id);
128end
129$$
130create trigger po_order_line_bu before update on po_order_line
131for each row
132begin
133call check_pk_order(NEW.po_id);
134call check_pk_inventory(NEW.item_id);
135end
136$$
137#
138# Application helpers
139#
140create procedure po_create_order(
141in p_cust_type char,
142in p_cust_id integer,
143out id integer)
144begin
145insert into po_order set cust_type = p_cust_type, cust_id = p_cust_id;
146set id = last_insert_id();
147end
148$$
149create procedure po_add_order_line(
150in po integer,
151in line integer,
152in item integer,
153in q integer)
154begin
155insert into po_order_line set
156po_id = po, line_no = line, item_id = item, qty = q;
157end
158$$
159#
160# Create sample data
161#
162insert into ab_physical_person values
163( 1, "John", "A", "Doe"),
164( 2, "Marry", "B", "Smith")
165;
166insert into ab_moral_person values
167( 3, "ACME real estate, INC"),
168( 4, "Local school")
169;
170insert into in_inventory values
171( 100, "Table, dinner", 5),
172( 101, "Chair", 20),
173( 200, "Table, coffee", 3),
174( 300, "School table", 25),
175( 301, "School chairs", 50)
176;
177select * from ab_physical_person order by person_id;
178person_id	first_name	middle_initial	last_name
1791	John	A	Doe
1802	Marry	B	Smith
181select * from ab_moral_person order by company_id;
182company_id	name
1833	ACME real estate, INC
1844	Local school
185select * from in_inventory order by item_id;
186item_id	descr	stock
187100	Table, dinner	5
188101	Chair	20
189200	Table, coffee	3
190300	School table	25
191301	School chairs	50
192#
193# Entering an order
194#
195set @my_po = 0;
196/* John Doe wants 1 table and 4 chairs */
197call po_create_order("P", 1, @my_po);
198call po_add_order_line (@my_po, 1, 100, 1);
199call po_add_order_line (@my_po, 2, 101, 4);
200/* Marry Smith wants a coffee table */
201call po_create_order("P", 2, @my_po);
202call po_add_order_line (@my_po, 1, 200, 1);
203#
204# Entering bad data in an order
205#
206call po_add_order_line (@my_po, 1, 999, 1);
207ERROR 45000: Failed integrity constraint, table in_inventory, PK:999
208#
209# Entering bad data in an unknown order
210#
211call po_add_order_line (99, 1, 100, 1);
212ERROR 45000: Failed integrity constraint, table po_order, PK:99
213#
214# Entering an order for an unknown company
215#
216call po_create_order("M", 7, @my_po);
217ERROR 45000: No such moral person, PK:7
218#
219# Entering an order for an unknown person type
220#
221call po_create_order("X", 1, @my_po);
222ERROR 45000: No such person type:X
223/* The local school wants 10 class tables and 20 chairs */
224call po_create_order("M", 4, @my_po);
225call po_add_order_line (@my_po, 1, 300, 10);
226call po_add_order_line (@my_po, 2, 301, 20);
227select * from po_order;
228po_id	cust_type	cust_id
2291	P	1
2302	P	2
2313	M	4
232select * from po_order_line;
233po_id	line_no	item_id	qty
2341	1	100	1
2351	2	101	4
2362	1	200	1
2373	1	300	10
2383	2	301	20
239SELECT * FROM ab_physical_person;
240person_id	first_name	middle_initial	last_name
2411	John	A	Doe
2422	Marry	B	Smith
243SELECT * FROM ab_moral_person;
244company_id	name
2453	ACME real estate, INC
2464	Local school
247select po_id as "PO#",
248( case cust_type
249when "P" then concat (pp.first_name,
250" ",
251pp.middle_initial,
252" ",
253pp.last_name)
254when "M" then mp.name
255end ) as "Sold to"
256  from po_order po
257left join ab_physical_person pp on po.cust_id = pp.person_id
258left join ab_moral_person mp on po.cust_id = company_id
259;
260PO#	Sold to
2613	Local school
2621	John A Doe
2632	Marry B Smith
264select po_id as "PO#",
265ol.line_no as "Line",
266ol.item_id as "Item",
267inv.descr as "Description",
268ol.qty as "Quantity"
269  from po_order_line ol, in_inventory inv
270where inv.item_id = ol.item_id
271order by ol.item_id, ol.line_no;
272PO#	Line	Item	Description	Quantity
2731	1	100	Table, dinner	1
2741	2	101	Chair	4
2752	1	200	Table, coffee	1
2763	1	300	School table	10
2773	2	301	School chairs	20
278drop database demo;
279