I have a question regarding my database design and its implementation that i am hoping someone can help me with?
I have a product -> retailer scenario where by the following rules apply:
product - many retailers
product - 1 brand
retailer - many products
Price can change per retailers
so i have 4 tables
product - (Product_ID), product name, brand_ID(FK), details
brand - (Brand_ID), brand name
retailer - (Retailer_ID), retailer_Name, Retailer_Telephone
Retailer_Product - (Product_ID, Retailer_ID), cost,
This works fine as you can associate products with reatilers and not all retailers offer all products etc. each product has a set brand.
My issues comes based on the brand:
a retailer can offer 1 or more brands but not necessarily all brands? i am getting an issue implementing this?
So i have created a Retailer_Brand table
retailer_brand - (retailer_Id, Brand_ID)
Even if you have specified the retailer to brand link i can still enter a product into the retailer product table that is of a brand not associated with the retailer. Am i missing something like a check constraint or is my schema wrong?
Thanks
Rob
*EDIT further details *
I am still not sure if it gives me what I require.
Perhaps If I add the following example it will clarify.
I have a list of products setup that we can offer
e.g.
Name Desc Brand
TV 32 Inch Sony
TV 64 Inch Sony
TV 20 Inch Sony
TV 64 Inch Samsung
TV 32 Inch Samsung
TV 32 Inch Panasonic
Retailers
Uberhardware - Can sell all brands of tv
SonyRetailer - Is only allowed to sell Sony products (all products)
PanasonicRetailer - Panasonic Products only
Then along comes a new retailer who I need to setup:
Phoenix Retail - Is not allowed to sell Sony products
I wish to be able to easily restrict/enable the different brands per retailer?
EDIT 2
I have implemented the Alternate key design suggested but i am still able to enter incorrect date see my data setup below and the expected results however all enrtsy into the retailer product table succeed when i would expect some to fail?
Product
ProductID BrandID
1 1
2 2
Brand
BrandID
1
2
Reatiler
1
2
RetailerBrand
RetailerID BrandID
1 1
2 1
2 2
3 1
RetailerProduct
RetaileID Brand ProductID Expected
1 1 1 OK
1 2 2 FAIL
2 1 1 OK
2 2 2 OK
3 2 2 FAIL
Alternate key (AK) -- unique constraint (with index) on Product allows (ProductID, BrandID) to be referenced from RetailerProduct as a FK.
create table Product (
ProductID integer not null
, BrandID integer not null
);
alter table Product add constraint pk_product primary key (ProductID);
alter table Product add constraint un_product unique (ProductID, BrandID);
create table Brand (
BrandID integer not null
);
alter table Brand add constraint pk_brand primary key (BrandID);
create table Retailer (
RetailerID integer not null
);
alter table Retailer add constraint pk_retailer primary key (RetailerID);
create table RetailerBrand (
RetailerID integer not null
, BrandID integer not null
);
alter table RetailerBrand add constraint pk_retbra primary key (RetailerID, BrandID);
create table RetailerProduct (
RetailerID integer not null
, ProductID integer not null
, BrandID integer not null
);
alter table RetailerProduct add constraint pk_retprd primary key (RetailerID, ProductID, BrandID);
alter table RetailerProduct add constraint fk1_retprd
foreign key (ProductID, BrandID) references Product (ProductID, BrandID);
alter table RetailerProduct add constraint fk2_retprd
foreign key (RetailerID, BrandID) references RetailerBrand (RetailerID, BrandID);
EDIT
Insert some data
insert into Brand (BrandID) values (1) , (2);
insert into Product (ProductID, BrandID) values (1,1), (2,2);
insert into Retailer (RetailerID) values (1) , (2);
insert into RetailerBrand (RetailerID, BrandID) values (1,1), (2,1), (2,2), (3,1);
Test
insert into RetailerProduct (RetailerID, BrandID, ProductID) values (1,1,1); -- OK
insert into RetailerProduct (RetailerID, BrandID, ProductID) values (1,2,2); -- FAIL
insert into RetailerProduct (RetailerID, BrandID, ProductID) values (2,1,1); -- OK
insert into RetailerProduct (RetailerID, BrandID, ProductID) values (2,2,2); -- OK
insert into RetailerProduct (RetailerID, BrandID, ProductID) values (3,2,2); -- FAIL
Let me see if I get this right.
Product
product_id
name
description
etc
Brand
brand_id
name
etc
Retailer
retailer_id
name
etc
Relational table
brand_prod_ret
retailer_id
product_id
brand_id
price
etc
For example, Uberhardware retailer sells TVs: LG, Sony, Samsung, etc.
Uberhardware goes in the Retailer table
TVs goes into the Product table
You have product_id matched with retailer_id and brand_id in the brand_prod_ret table.
Into brands you have LG, Sony, Samsung, etc.
and into brand_prod_ret you have
TVs' ID - Sony's id -Uberhardware id
TVs' ID - Samsung's id - Uberhardware id
TVs' ID - LG's id - Uberhardware id
and of course each price.
Now you can know exactly which brand the retailer is selling at the moment
Is there any reason the brand table is needed in this capacity?
We have many to many relationships with
products - brand
retailer - retailer_product
brand - retailer brand
Seems you could keep the brand info in the retailer_product table. Then every new brand entered could be pk linked. Or only a retailer to brand look up table to enforce the constraint of a retailer association b/f a new retailer_product can be entered
IMO in your current structure, the table retailer_brand is not strictly necessary, as you can always determine which brands are fully or partially stocked by a retailer by navigating through the retailer_product => product => brand relations.
Can I ask for some clarification on your business domain which might impact your data modelling? (I have some experience at a retailer), e.g.
Brands are often retailer-specific (i.e. a Supplier manufactures a line of products branded purely for one retailer). You might consider adding a Supplier table to your model.
Often stores within the retailer's chain do not stock all products. You might need to consider this in your model.
I'm not sure whether you are on the consumer or supplier facing side of the business, but you may need to model both a cost price and a selling price.
Prices should include Date From / Date To
etc.
Related
Suppose I have two tables: A (with columns: a,b,c,d) and B (with columns: x,y,z). Now, (a,b) together make the primary key for table A and x is the primary key of table B. Is it possible to make b a foreign key of table A that refers x from table B?
Please reply ASAP!
Thanks in advance! :-)
Yes, there is no issue with that. A classic example (using MySQL for demonstration purposes) is a database table holding a number of companies and another holding employees which can work for any one of those companies:
create table companies (
id int primary key,
name varchar(20));
create table employees (
id int,
c_id varchar(20) references companies(id),
name varchar(20),
primary key (id, c_id));
insert into companies (id, name) values (1, 'ABC');
insert into companies (id, name) values (2, 'DEF');
insert into companies (id, name) values (3, 'HIJ');
insert into employees (id, c_id, name) values (101, 1, "Allan");
insert into employees (id, c_id, name) values (102, 1, "Bobby");
insert into employees (id, c_id, name) values (101, 2, "Carol");
insert into employees (id, c_id, name) values (101, 3, "David");
Note that the primary key for employees is a composite key made up of the employee ID and company ID. Note also that the company ID is a foreign key constraint on the primary key of companies, the exact situation (functionally) that you asked about.
The query showing who works for what company shows this in action:
select c.id, c.name, e.id, e.name
from companies c, employees e
where c.id = e.c_id
order by c.id, e.id
c.id c.name e.id e.name
---- ------ ---- ------
1 ABC 101 Allan
1 ABC 102 Bobby
2 DEF 101 Carol
3 HIJ 101 David
Can a column in a composite primary key also be a foreign key referencing a primary key of another table? Of course it can. The important question is, when is this a good idea?
The most common scenario is probably the intersection or junction table. Customers can have more than one Address (Shipping, Billing, etc) and Addresses can have more than one Customer using them. So the table CUSTOMER_ADDRESSES has a primary key which references both CUSTOMER and ADDRESS primary key (and for bonus points the ADDRESS_TYPE reference data table too).
My examples use Oracle 12c syntax:
create table customer_address
( customer_id number(38,0) not null
, address_id number(38,0) not null
, address_type_code varchar2(3) not null
, constraint customer_address_pk primary key
(customer_id, address_id, address_type_code)
, constraint customer_address_customer_fk foreign key
(customer_id) references customer(customer_id)
, constraint customer_address_address_fk foreign key
(address_id) references address(address_id)
, constraint customer_address_type_fk foreign key
(address_type_code) references address_type(address_type_code)
);
The second scenario occurs when the primary key of the child table is comprises the parent key and an identifier (usually a number) which is only unique within the parent key. For instance, an Order has an Order Header and some Order Lines. The Order is identified by the Order Header ID and its lines are identified by a monotonically incrementing number. The ORDER_LINE table may look like this:
create table order_line
( order_header_id number(38,0) not null
, order_line_no number(38,0) not null
, product_id number(38,0) not null
, qty number(38,0) not null
, constraint order_line_pk primary key
(order_header_id, order_line_no)
, constraint order_line_header_fk foreign key
(order_header_id) references order_header(order_header_id)
, constraint order_line_product_fk foreign key
(product_id) references product(product_id)
);
Note that we could model ORDER_LINE as another intersection table, with a primary key of (order_header_id, product_id) and relegate order_line_no to the status of ordinary attribute: it depends on the business rules we must represent.
This second scenario is rarer than you might think: composite primary keys are pretty rare in real life. For instance, I think the model presented in that other answer is weak. The chances are we will need to use Employee as a foreign key for a number of relationships (e.g. Manager, Assignment, Sales). Using a composite key for foreign keys is clumsy (more typing!). Furthermore, when we drill into these models we often find that one of the key columns is a natural key rather than a primary key, and so might be subject to change. Cascading changes to natural key columns in composite foreign keys is a PITN.
Hence it is common practice to use a surrogate (or synthetic) primary key, say using a sequence or identify column, and enforce the natural key with a unique constraint. The latter step is often forgotten but it is crucial to maintaining referential integrity. Given a situation in which we need to store details of Employees from several Companies, including the Companies' Employee Identifier we might have an EMPLOYEE table like this:
create table employee
( employee_id number(38,0) generated always as number
, company_id number(38,0) not null
, company_employee_id varchar2(128) not null
, name varchar2(128) not null
, constraint employee_pk primary key
(employee_id)
, constraint employee_uk unique
(company_id, company_employee_id)
, constraint employee_company_fk foreign key
(company_id) references company(company_id)
);
One situation where it is common to find composite primary keys cascaded to dependent tables is in data warehouses and other VLDBs. Here the composite key columns form part of a denormalization strategy to support Partitioning schemes and/or efficient access paths.
I'm not a DBA and I don't know what is the best solution. I have two tables,
Custumers Table
CustomerId (primary key, identity)
...
and
Suppliers Table
SupplierId (primary key, identity)
...
and I want to store multiple telephone number and multiple emails. I thought to create two other tables, Emails and Telephones and use those in join with my Custumers and Suppliers, something like
Telephones Table
Id
UserId (reference to SuppliersId or CustomerId)
Value
...
But if I use as key for custumers and suppliers an Identity I'll have for sure problems. I'm thinking to do something like
Telephones Table
Id
SuppliersId
CustumersId
Value
...
But I don't know if is a good design. Any advice?
Thank you
One idea:
Entity (ID (PK), {common fields})
Customer (ID (PK), EntityID (FK), {other fields})
Supplier (ID (PK), EntityID (FK), {other fields})
Telephone (ID (PK), EntityID (FK), Value)
This also has the added advantage of reducing duplication between Customer and Supplier.
A good design would be
Customers: Table of customers - CustomerId, Other columns
Suppliers: Table of suppliers - SupplierId, Other columns
Telephones: Table of telephones - TelephoneId, other columns
CustomerTelephones: CustomerId, TelephoneId
SupplierTelephones: SupplierId, TelephoneId
my advise is that you assign an ID for the table then add a reference field with the same datatype with the SupplierID and CustomerID
The other answers are decent beginner solutions, but they all have the same fundamental flaw in that Customer or Supplier are Relationships and not their own unique entities. A Customer is not a person, it's a relationship between you and a person.
In fact a person could be an Employee, Customer, Supplier all at the same time, or over time.
A Customer or Supplier could also be a Business, with many involved people.
Here is the correct answer:
PARTY
id
type {individual, organization, automated_agent}
org_name null
first_name null
last_name null
PARTY_RELATIONSHIP
from_party_id FK PARTY
type {supplier_of, customer_of, ...}
to_party_id FK PARTY
from_date
to_date null
Usage:
Insert into party (id, type, org_name) values (1, 'organization', 'Raw Steel Co');
Insert into party (id, type, f_name, last_name) values (2, 'individual', 'Davide', 'X');
-- Raw Steel Co is both a customer of and supplier to you:
Insert into party_relationship values (1, 'supplier_of', 2, getdate(), null);
Insert into party_relationship values (1, 'customer_of', 2, getdate(), null);
Now, some people don't like Single Table Inheritance because of the nulls, but goddam it is easier to work with. Use Class Table Inheritance if you're finicky.
The 'type' columns should be foreign keys to type tables.
you can do like
Customers: Table of customers - CustomerId, Other columns
Suppliers: Table of suppliers - SupplierId, Other columns
Telephones: Table of telephones - TelephoneId,TypeId,TypeName, other columns
where TypeName will be Customers or Suppliers, ant TypeId will be id of the resp.
I've mostly used MyISAM tables before, which don't support foreign keys. Looking on stack overflow I didn't find a nice, concise explanation of what a foreign key is actually doing. I'm mostly interested in join tables, where you would have a schema like this:
customers
id category_id
products
id category_id
categories
id
customerproducts
customer_id product_id
If I have foreign keys on customerproducts, it will ensure that only valid customers and only valid products get into that table, but what about if I try to add a Product from the phones category to a customer earmarked as one only interested in copiers? Will this cause the foreign key constraints to be violated?
I'm mostly interested in join tables, where you would have a schema like this:
You wouldn't have a schema like that--it doesn't represent the facts you're interested in. Let's sketch out some tables in SQL. (Tested in PostgreSQL) First, customers and products.
-- Customer names aren't unique.
create table customers (
cust_id integer primary key,
cust_name varchar(15) not null
);
insert into customers values (1, 'Foo'), (2, 'Bar');
-- Product names are unique.
create table products (
prod_id integer primary key,
prod_name varchar(15) not null unique
);
insert into products values
(150, 'Product 1'), (151, 'Product 2'), (152, 'Product 3');
There are different categories for products.
create table categories (
cat_name varchar(15) primary key
);
insert into categories values ('Cable'), ('Networking'), ('Phones');
Each product might appear in several categories.
create table product_categories (
prod_id integer not null references products,
cat_name varchar(15) not null references categories,
primary key (prod_id, cat_name)
);
insert into product_categories values
(150, 'Cable'), (150, 'Networking'), (151, 'Networking'), (152, 'Phones');
A customer might be interested in several categories of products.
create table customer_category_interests (
cust_id integer not null references customers,
cat_name varchar(15) not null references categories,
primary key (cust_id, cat_name)
);
-- Nobody's interested in phones
insert into customer_category_interests values
(1, 'Cable'), (1, 'Networking'), (2, 'Networking');
If I have foreign keys on customerproducts, it will ensure that only
valid customers and only valid products get into that table, but what
about if I try to add a Product from the phones category to a customer
earmarked as one only interested in copiers?
Customers aren't interested in every product in their preferred categories. Note the overlapping foreign key constraints.
create table product_interests (
cust_id integer not null,
prod_id integer not null,
cat_name varchar(15) not null,
foreign key (cust_id, cat_name) references customer_category_interests,
foreign key (prod_id, cat_name) references product_categories,
primary key (cust_id, prod_id, cat_name)
);
insert into product_interests values
(1, 150, 'Cable'), (2, 150, 'Networking');
This next insert will fail, because customer 1 isn't interested in phones.
insert into product_interests values
(1, 152, 'Phones');
ERROR: insert or update on table "product_interests" violates foreign key constraint "product_interests_cust_id_fkey"
DETAIL: Key (cust_id, cat_name)=(1, Phones) is not present in table "customer_category_interests".
I'm wondering if this would be the best way to build a table for an item that can have more than 1 price. Each product is identified by its model_number. Should I use a prefix before the model_number for each individual seller? I can't use model_number for the primary key. For example:
seller_product_id model_number seller price
SELLER_1_MODEL_NUMBER MODEL_NUMBER seller_1 9.99
SELLER_2_MODEL_NUMBER MODEL_NUMBER seller_2 19.99
For the sake of loose coupling, I suggest you build seperate Items and Price tables, and have another table (called Junction table) Item_Price which maps many items to many prices as you like.
This is called Many-to-Many relationship
Basically, it links an Item with its itemId to a Price with priceId, and stores this link in an Item_Price itemPriceId (or whatever you call the 3rd primary key)
Here's a sample diagram EDIT: sorry about the previous diagram.
Here's a sample SQL DDL of 3 tables, plus 2 junction tables to associate Item to Price, and Seller to Item.
CREATE TABLE Item (
item_id int PRIMARY KEY,
..
..
)
CREATE TABLE Price (
price_id int PRIMARY KEY,
..
..
)
CREATE TABLE Seller (
seller_id int PRIMARY KEY,
..
..
)
-- This is the junction table for Item to Price mapping.
CREATE TABLE Item_Price (
item_id int REFERENCES Item (item_id),
price_id int REFERENCES Price (price_id),
PRIMARY KEY (item_id, price_id)
)
-- This is the junction table for Seller to Item mapping.
CREATE TABLE Seller_Item (
seller_id int REFERENCES Seller (seller_id),
item_id int REFERENCES Item (item_id),
PRIMARY KEY (seller_id, item_id)
)
One attribute that have many properties? Sounds like one-to-many relations... go for a new table have foreign key help you out.
Products
prod_id (PK) | model_no
Sellers
seller_id(PK)|seller_name
Pricing
price_id (PK)|price|prod_id (FK) | seller_id(FK)
yes You can a prefix before the model_number for each individual seller.
If you still have stuff then let me know more clear your problem
I went through many threads and couldn't figure it out. Sorry if this is a duplicate question. Consider the following setup.
1) Employee => (ID,Name)
2) Department => (ID,Name,location,Clerk,Accountant,Middle-manager,Group-manager,Regional-manager,Active)
Department can have many Clerks, Accountants, Middle-managers and so on. They are just employees from the Employee table. Need a better database schema (flexible like, adding up a new column as Divisional-Manager must be easy) for Department entity with NO data duplication, NO update anomalies and NO / less junction tables.
Thanks in advance! :)
You need something like this;
CREATE TABLE department(
dept_id int NOT NULL,
dept_name char(10) NULL,
CONSTRAINT PK1 PRIMARY KEY NONCLUSTERED (dept_id)
)
go
CREATE TABLE department_employee(
id int NOT NULL,
dept_id int NOT NULL,
emp_id int NOT NULL,
CONSTRAINT PK3 PRIMARY KEY NONCLUSTERED (id)
)
go
CREATE TABLE employee(
emp_id int NOT NULL,
emp_name char(10) NULL,
CONSTRAINT PK2 PRIMARY KEY NONCLUSTERED (emp_id)
)
go
ALTER TABLE department_employee ADD CONSTRAINT Refdepartment1
FOREIGN KEY (dept_id)
REFERENCES department(dept_id)
go
ALTER TABLE department_employee ADD CONSTRAINT Refemployee2
FOREIGN KEY (emp_id)
REFERENCES employee(emp_id)
go
You have a many-to-many relationship so you need a third association (junction) table - you can't avoid it.
DepartmentMember => (DepartmentId, EmployeeId, MembershipRole)
Why don't you want this?
Employee =>(ID,name, department_ID, position_ID, Active)
Position =>(ID, name, Active)
Department => (ID,Name,location,Active)
Department =>(ID,employeeID,location,active)
Employee =>(EmployeeID,name, position)
I think that would be a much better way of organizing your tables. This assumes that active is a property of the department, else move it to the employee table.
Assuming an employee can only work in 1 department. IF not, then yes, you need a third table to avoid duplication
Employee
ID, Name, EmployeeType, DepartmentID
(pk on ID, EmployeeType)
Department
ID, Name, Active
Position/Title is very much contextual
to Department. One can be a
Regional-Manager in one department and
can additionally takes Consultant
position in another department.
Then , the department and the Employee is many-to-many. The Employee to the position is also many-to-many. If you need flexibility ,like adding a new title for a department , the junction tables are necessary. You cannot avoid it.
You can refer to the following Table structure for reference:
Employee
-----------------------
EmployeeID (PK)
EmployeeName
Active
Department
-------------------------
DepartmentID (PK)
DepartmenName
Location
Position
----------------------------
PositionID (PK)
PositionDescription (eg.Clerk, Accountant etc)
EmployeePosition
----------------------------
EmployeeID (FK to Employee.EmployeeID )
DepartmentID (FK to Department.DepartmentID)
PositionID (FK to Position.PositionID )
If the Position/Title is fixed to
Employee instead of Department.i.e. An
employee who is clerk and can be in
that position to one or many dept.,
how can we go about it?
Do you mean that in an extreme case , many employees can have their own special titles ? and they belong to many departments? If yes ,suppose a employee ID 123 has a special title called "The Special One" , and it belongs to the IT , Account and Sales department . You first create this title (i.e "The Special One" ) in the Position table and get the Position.PositionID.
Then you insert 3 records for Employee.EmployeeID 123 into EmployeePosition table using this Position.PositionID and the Department ID of IT , Account , Sales departments.