If this is your first visit, be sure to check out the FAQ by clicking the link above. You may have to register before you can post: click the register link above to proceed. To start viewing messages, select the forum that you want to visit from the selection below.

 
Go Back  dBforums > General > Database Concepts & Design > Data Modeling issue

Reply
 
LinkBack Thread Tools Search this Thread Display Modes
  #1 (permalink)  
Old 05-11-08, 01:46
y0ssarian87 y0ssarian87 is offline
Registered User
 
Join Date: May 2008
Posts: 11
Data Modeling issue

Hey, guys, I'm working on building a database for my step-mom's chocolate shop. I just took a database course, and that was my inspiration, but clearly, I didn't pick up on how to address this issue. I am trying to create an appropriate data model, but I'm having some trouble modeling the purchasing/B2B aspect of the business. Here is what I've got so far:

I know that each ingredient she uses can be bought from multiple vendors, and each vendor sells multiple ingredients. This many-to-many relationship is then given a look-up table "Vendor_Ingredient" with the Vendor_ID and the Ingredient_ID as a composite primary key (or at least it's unique if you use a surrogate key) with price as an attribute.

I know that when she places a purchase order, it is only sent to one vendor. Each purchase order also has many ingredients on it, and any ingredient can also be on many purchase orders. I know that really what she is purchasing (in the sense of data modeling) is not just an ingredient, but an ingredient from a specific vendor at a price that's dependent on the ingredient and vendor. So, there is a many-to-many relationship between purchase order and "Vendor_Ingredient."

And this is where I'm stuck. If every purchase order points to only one vendor, but the purchase order also points to many vendor ingredients (through a lookup table, of course), how can you enforce the integrity that a purchase order's "vendor_ingredients" only point to the vendor to whom the purchase order is being placed? Because its an integrity issue, I figure I must be violating a normal form, but I know that all these tables are in 3NF and BCNF; I don't really know how to enforce integrity for the higher normal forms (if that's even the issue). If it's not a normal form violation, what can I do to make sure that a purchase order's ingredients are pointing to the same vendor as that to which the purchase order is being sent?

Thanks for all and any help!
Reply With Quote
  #2 (permalink)  
Old 05-11-08, 07:24
r937 r937 is offline
SQL Consultant
 
Join Date: Apr 2002
Location: Toronto, Canada
Posts: 19,524
Quote:
Originally Posted by y0ssarian87
how can you enforce the integrity that a purchase order's "vendor_ingredients" only point to the vendor to whom the purchase order is being placed?
in practical terms, by not choosing any other vendor's ingredients

a database application has to have a "front end" -- where the user makes choices

to create a purchase order, the user has to decide to do so, and initiate some action in the front end app to get the process started

when the user decides to place a purchase order with vendor X, then the front end app should only show vendor X's products from which to select, and these selections decide which rows get created in the vendor_ingredients table

simple, really

on the database side, you could use a CHECK constraint, but this would be needed only if you felt there was a possibility that you would get new vendor_ingredients from someplace other than your front end app and needed to ensure the integrity at the database level
__________________
r937.com | rudy.ca
please visit Simply SQL and buy my book
Reply With Quote
  #3 (permalink)  
Old 05-11-08, 15:28
y0ssarian87 y0ssarian87 is offline
Registered User
 
Join Date: May 2008
Posts: 11
Integrity Enforcement

Thanks for your prompt reply!

Perhaps it's just the theory of it that's got me hung-up, but for some reason I feel like integrity should be enforced completely at the database level. Is that an unreasonable expectation of the DBMS? You're right that there is (that I know of) no instance in which the front-end app wouldn't supply the vendor's ingredients, but I feel uncomfortable leaving the integrity of the model up to an application.

Also, how could a CHECK constraint work in this instance? You can't use a CHECK constraint across tables, so in my "PO_Vendor_Item" look-up table that links Purchase Orders to the Vendor's Items, how could you create a CHECK constraint without referring back to the "Purchase_Order" table to see the Vendor Foreign Key?

Let's say I want to enforce as much integrity as possible through the database. Could I use triggers? If so, how?

Again, thanks to all who read and reply!
Reply With Quote
  #4 (permalink)  
Old 05-11-08, 16:26
Pat Phelan Pat Phelan is offline
Resident Curmudgeon
 
Join Date: Feb 2004
Location: In front of the computer
Posts: 12,605
If your mom can order a thinga-mabob from more than one vendor, I say let her buy it from whoever she chooses. Particularly for a small business, having the ability to purchase when/where/how they need to purchase is very important.

While it is technically possible to limit the choice, for this kind of business that would be a potentially fatal business mistake.

-PatP
Reply With Quote
  #5 (permalink)  
Old 05-11-08, 16:42
y0ssarian87 y0ssarian87 is offline
Registered User
 
Join Date: May 2008
Posts: 11
Thanks

No, I completely agree, I just wanted to make sure that each purchase order and each item on that purchase order was pointing to the one vendor. If she wanted to buy the same item from a different vendor she would just have another purchase order. But I figured it out. Here was what I had:

Vendor
--------------
Vendor_ID PK
...


Ingredient
----------------
Ingredient_ID PK
...


Vendor_Ingredient
--------------------------
Vendor_ID PK, FK
Ingredient_ID PK, FK
Cost

Purchase_Order
------------------------
PO_Number PK
Vendor_ID FK /* The vendor is here because each purchase order only belongs to one vendor. */
...

PO_Vendor_Item
-------------------------
PO_Number PK, FK
Vendor_ID PK, FK
Ingredient_ID PK, FK
/* The SQL for this being:
FOREIGN KEY (Vendor_ID, Ingredient_ID) references Vendor_Ingredient (Vendor_ID, Ingredient_ID),
PRIMARY KEY (PO_Number, Vendor_ID, Ingredient_ID) */

But, clearly, a PO_Vendor_Item tuple can have a PO_Number that points to a particular vendor, but it might not match the Vendor_ID in "PO_Vendor_Item."

Here was the solution I created, and I think it works much better. Any thoughts?

Vendor
--------------
Vendor_ID PK
...


Ingredient
----------------
Ingredient_ID PK
...


Vendor_Ingredient
--------------------------
Vendor_ID PK, FK
Ingredient_ID PK, FK
Cost

Purchase_Order
------------------------
PO_Number PK
Vendor_ID PK, FK /* See, here Vendor_ID is now part of the PK. This means we can use it as part of the foreign key in PO_Vendor_Item*/
...

PO_Vendor_Item
-------------------------
PO_Number PK, FK
Vendor_ID PK, FK
Ingredient_ID PK, FK references Ingredient_ID
/* The SQL for this being:
FOREIGN KEY (PO_Number, Vendor_ID) references Purchase_Order (PO_Number, Vendor_ID),
PRIMARY KEY (PO_Number, Vendor_ID, Ingredient_ID) */
Reply With Quote
  #6 (permalink)  
Old 05-11-08, 16:43
y0ssarian87 y0ssarian87 is offline
Registered User
 
Join Date: May 2008
Posts: 11
P.S. the changes are marked in red in case you didn't pick that up! Thanks again for everyone who helped!
Reply With Quote
  #7 (permalink)  
Old 05-11-08, 16:47
r937 r937 is offline
SQL Consultant
 
Join Date: Apr 2002
Location: Toronto, Canada
Posts: 19,524
you could always use triggers, yes

i understand what you're saying about the CHECK constraint not working across tables, but i would try CHECK(SELECT MIN(vendor_id) = MAX(vendor_id)) or something like that

alternatively, you could use an ASSERTION, except of course no database system supports it today
__________________
r937.com | rudy.ca
please visit Simply SQL and buy my book
Reply With Quote
  #8 (permalink)  
Old 05-11-08, 17:02
y0ssarian87 y0ssarian87 is offline
Registered User
 
Join Date: May 2008
Posts: 11
Oh, no, wait. Crap. This still doesn't work. Now an item can be ordered from a vendor even if they don't sell that item. Back to square one. Any ideas?
Reply With Quote
  #9 (permalink)  
Old 05-11-08, 17:30
y0ssarian87 y0ssarian87 is offline
Registered User
 
Join Date: May 2008
Posts: 11
is this a feasible solution??

How bout this solution:

Vendor
--------------
Vendor_ID PK
...


Ingredient
----------------
Ingredient_ID PK
...


Vendor_Ingredient
--------------------------
Vendor_ID PK, FK
Ingredient_ID PK, FK
Cost

Purchase_Order
------------------------
PO_Number PK
Vendor_ID FK /* The vendor is here because each purchase order only belongs to one vendor. */
...

PO_Vendor_Item
-------------------------
PO_Number PK, FK
Vendor_ID PK, FK
Ingredient_ID PK, FK
/* The SQL for this being:
FOREIGN KEY (Vendor_ID, Ingredient_ID) references Vendor_Ingredient (Vendor_ID, Ingredient_ID),
FOREIGN KEY (PO_Number, Vendor_ID) references Purchase_Order (PO_Number, Vendor_ID),
PRIMARY KEY (PO_Number, Vendor_ID, Ingredient_ID) */
Reply With Quote
  #10 (permalink)  
Old 05-11-08, 17:31
y0ssarian87 y0ssarian87 is offline
Registered User
 
Join Date: May 2008
Posts: 11
Crap, I just copied and pasted the old one. Just pretend that Purchase_Order has a composite PK of PO_Number and Vendor_ID
Reply With Quote
  #11 (permalink)  
Old 05-11-08, 17:42
r937 r937 is offline
SQL Consultant
 
Join Date: Apr 2002
Location: Toronto, Canada
Posts: 19,524
Quote:
Originally Posted by y0ssarian87
Just pretend that Purchase_Order has a composite PK of PO_Number and Vendor_ID
which would allow you to enter PO_Number 1234 with Vendor_ID 567, and a separate row with PO_Number 1234 with Vendor_ID 789
__________________
r937.com | rudy.ca
please visit Simply SQL and buy my book
Reply With Quote
  #12 (permalink)  
Old 05-11-08, 18:08
y0ssarian87 y0ssarian87 is offline
Registered User
 
Join Date: May 2008
Posts: 11
Unique

Not if you include a unique constraint on the PO Number!
Reply With Quote
  #13 (permalink)  
Old 05-11-08, 23:45
blindman blindman is offline
World Class Flame Warrior
 
Join Date: Jun 2003
Location: Ohio
Posts: 11,726
Yosarian,
What database platform are you using?
You will have a table of purchase order items linking purchase orders to vendor items. In SQL Server you could create an indexed view to enforce the constraint that a single purchase order can have items from only one vendor.
__________________
If it's not practically useful, then it's practically useless.

blindman
www.chess.com: "sqlblindman"
Reply With Quote
  #14 (permalink)  
Old 05-11-08, 23:59
y0ssarian87 y0ssarian87 is offline
Registered User
 
Join Date: May 2008
Posts: 11
Dbms

Hey Blindman,

To be honest, I'm using both Oracle and MySQL. On my laptop I'm using MySQL, but since (and as I conveniently left out) this project is for my final project for a class that uses Oracle, I'm really trying to make this work for Oracle.

I found a perfectly viable solution, though, I believe, using both Oracle and MySQL (or any DBMS, for that matter), so I'm gonna stick with that.

Here's a section of my code (for MySQL); tell me what you think:

CREATE TABLE Ingredients(
Ingredient_ID int(4) AUTO_INCREMENT PRIMARY KEY,
Ingredient_Name varchar(30) NOT NULL,
Description varchar(100),
Std_Unit_Amount float(5,2) NOT NULL,
/* Std_Unit_Amount should be measured in oz. for solids and fl. oz. for liquids. */
Units_to_Reorder int(2) NOT NULL,
Units_on_Hand int(4) NOT NULL,
Reorder_Unit_Point int(3) NOT NULL);

CREATE TABLE Vendors(
Vendor_ID int(4) AUTO_INCREMENT PRIMARY KEY,
Vendor_Name varchar(30) NOT NULL,
Main_Contact varchar(40),
Phone_Number bigint(10) NOT NULL,
Fax_Number bigint(10),
Address1 varchar(30) NOT NULL,
Address2 varchar(30),
City varchar(20) NOT NULL,
State varchar(2) NOT NULL,
Zip int(5) NOT NULL,
Comments varchar(50));

CREATE TABLE Vendor_Ingredient(
Vendor_ID int(4) NOT NULL references Vendors,
Ingredient_ID int(4) NOT NULL references Ingredients,
Cost float(5,2) NOT NULL,
PRIMARY KEY (Vendor_ID, Ingredient_ID));

CREATE TABLE Purchase_Order(
Purchase_Order_Num int(5) AUTO_INCREMENT PRIMARY KEY);

CREATE TABLE Box_Order(
Box_Purch_Ord_Num int(5) PRIMARY KEY references Purchase_Order,
Date_Placed date NOT NULL,
Sales_Order_Num varchar(15));

CREATE TABLE Ingredient_Order(
Ing_Purch_Ord_Num int(5) NOT NULL UNIQUE references Purchase_Order,
Date_Placed date NOT NULL,
Sales_Order_Num varchar(15),
Vendor_ID int(4) NOT NULL references Vendors,
PRIMARY KEY (Ing_Purch_Ord_Num, Vendor_ID));

CREATE TABLE Ingredient_Order_Item(
Ing_Purch_Ord_Num int(5) NOT NULL,
Vendor_ID int(4) NOT NULL,
Ingredient_ID int(4) NOT NULL,
Quantity int(3) NOT NULL,
FOREIGN KEY (Ing_Purch_Ord_Num, Vendor_ID) references Ingredient_Order (Ing_Purch_Ord_Num, Vendor_ID),
FOREIGN KEY (Vendor_ID, Ingredient_ID) references Vendor_Ingredient (Vendor_ID, Ingredient_ID),
PRIMARY KEY (Ing_Purch_Ord_Num, Vendor_ID, Ingredient_ID));
Reply With Quote
  #15 (permalink)  
Old 05-12-08, 06:32
r937 r937 is offline
SQL Consultant
 
Join Date: Apr 2002
Location: Toronto, Canada
Posts: 19,524
Quote:
Originally Posted by y0ssarian87
...but since (and as I conveniently left out) this project is for my final project for a class ...
scoundrel!!!
__________________
r937.com | rudy.ca
please visit Simply SQL and buy my book
Reply With Quote
Reply

Thread Tools Search this Thread
Search this Thread:

Advanced Search
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are On