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