SQL; How to insure data integrity in complex situations - sql

I have three tables named, Customer , Product , Sale . I need to know which products has been presented in which Sales and which customers have been attended to which Sales. So here is what we have so far:
Customer (Id, Name)
Product (Id, Name)
Sale(Id, Title, Date)
CustomerSale(Id, CustomerId, SaleId) //intermediate table
ProductSale(Id, ProductId, SaleId) //intermediate table
Also I need to know which customer likes (just imagine they can up-vote products!) which products in each Sale and also I need to know which customer mark which product as useful in each Sale. So I have two solutions:
Scenario 1: simply make an intermediate table between those two intermediate tables!
CustomerProduct(Id, customerSaleId, productSaleId, doesLikes, isUseful)
Scenario 2: make an intermediate with FK to three tables (Customer, Product, Sale)!
CustomerProduct(Id, SaleId, CustomerId, ProductId, doesLikes, isUseful)
Problem:
None of the above solutions insure data integrity because in scenario1 it is possible to insert customerSaleId and productSaleId which does not refer to the same Sale. In scenario2 it is possible to insert an invalid (Sale, Customer, Product) triple. because you cannot be sure whether the product is presented in that Sale or not moreover you cannot be sure the customer has attended to that sale or not.
So is there any better solution?

If you ignore the surrogate keys on CustomerSale and ProductSale and have scenario 2 reference the compound unique keys on these tables of (CustomerId, SaleId) and (ProductId, SaleId) respectively would this give you what you want?

I change your structure to this
Customer (Id, Name)
Product (Id, Name)
Sale(Id, CustomerId, Title, Date)
ProductSale(Id, ProductId, SaleId)
CustomerProduct(Id, productSaleId, doesLikes, isUseful)
isn't it better?

Related

How would I structure a database for taking sales orders?

I am helping someone build a grocery deliver service. Very simple site and order process. The problem I am having is knowing how to come up with schema for the orders. The order would have contact information, but would also need to have all of the products they ordered. Since it can/will be different for each persons order, how would I go about designing this? Would I just have a products ordered field with a string list of all the items? Or would I need multiple linked tables?
Thanks!
You need three tables:
a) Products - Contains the product details
b) Orders - Contains the order header, contact information etc
c) Product_Orders - is a table with two columns: product_id and order_id, that bind the orders to the products, and a quantity field and unit price.
You could have a customers table, but ideally information like the delivery address, etc, would be attached to the order so that if the user changes his address it will not affect your order history.
For the same reason unit price must be in Product_Orders, so that if a product price changes it does not affect previous orders.
Product table
with name and price of all products.
Customer table
with name, address, phone etc...
Order table
with entries for each order: order id, cusomer id, date etc
Order Items table
with all ordered items, with link to id in ordertable, product table, quantity, price, etc...

How do I insert a foreign key automatically without having to look it up myself?

I have three tables; customers, orders, products.
I want to insert which customer ordered which product into the orders table. So far I can only do this by manually looking at the customer_id and the product_id then using INSERT INTO orders(customer_id, product_id) VALUES ("3", "5); which will link customer number 3 to product number 5.
This works and I can SELECT out the data and it is fine. But I don't want to have to look at the numbers to enter the data. I just want to type the NAME of the customer and the NAME of the product and let SQL find and insert the correct keys for me. Surely this must be easy but I just can't figure it out.
Thanks all in advance.
Something like the following can help?
INSERT INTO orders(customer_id, product_id)
SELECT customer_id from customers where name = 'name1
UNION
SELECT product_id from products where name = 'name2'
Of course, the names should be unique.

normalization of a table

I have this table, i have to normalize up to 3nf
Assume the following:
An Order can contain multiple products
Everytime a customer places an Order, they get a new order number
An Order belongs to one and only one customer
Orders (OrderNum, OrderDate, (ProductId,ProductDesc),CustId,CustomerName,CustomerAddress)
So far i have done this
1FN
Orders (OrderNum, OrderDate, (ProductId,ProductDesc),(CustId,CustomerName,CustomerAddress, OrderNum))
2FN
Orders(OrderNum, OrderDate)
Orders_Product(OrderNum, ProductId)
Product(ProductId, ProductDesc)
Customer_Orders(OrderNum, CustId)
Customer(CustId,CustomerName,CustomerAddress)
3 NF
The tables already fulfill the 3NF
Orders(OrderNum, OrderDate)
Orders_Product(OrderNum, ProductId)
Product(ProductId, ProductDesc)
Customer_Orders(OrderNum, CustId)
Customer(CustId,CustomerName,CustomerAddress)
Dependencies
OrderNum  OrderDate,ProductId,ProductDesc,CustId, CustomerName, CustomerAddress
ProductId  ProductDesc
CustId  CustomerName, CustomerAddress
is it my 2NF and 3Nf correct?
Base on the definition from Wiki: a table is in 2NF if it is in 1NF and no non-prime attribute is dependent on any proper subset of any candidate key of the table. Most of your tables only have 2 columns, so they satisfied this. For Customer(CustId,CustomerName,CustomerAddress), the candidate key is CustId, and the other 2 columns completely depend on the whole candidate key, then it's OK.
For 3NF, Wiki said: all the attributes in a table are determined only by the candidate keys of that table and not by any non-prime attributes. As you see, your tables are all satisfied.
However, as you said:
An Order belongs to one and only one customer
So, I don't think you need Customer_Orders number. You should remove it, and place CustId in Orders table. So, your Orders table will look like this: Orders(OrderNum, OrderDate, CustId)

SQL Access with Table

It wont let me upload image but columns are OrderID, CustomerName, CustomerAddress, ProductNumber, SellDate, ProductDescription
I am trying to teach myself SQL. Could someone please help me identify a few things?
1) I want to write a SQL statement that retrieves the customer name and address of the customer that placed order 7.
Is this right?
Select CustomerName, Address
From Order
Where OrderID = ‘7’
2)Next I want to write an SQL statement that adds a new order to the Order table.
Is this right?
INSERT INTO order(OrderID, CustomerName, CustomerAddress, ProductNumber, SellDate, ProductDescription)
VALUES (8, 'Ben C', '12 Kents Road', 01/15/2012, Clay :));
3) What is wrong with this data model and how would you redesign it? I really need help here. Does it need to be sorted? How could I describe a new high level design?
4) How would I move this data from an old model to a new model?
5)Using the new data model, I need to write a JOIN that retrieves the customer name and address of the customer that placed order 7. I have not gotten here yet because I am not sure why the old data model is bad.
First, you need to answer a question:
Can a customer place more than one order? If your answer is 'yes', would you like to have a customer catalog?
In this scenario, you need to normalize your database. First of all, you need to separate the data into logical sets; in this case, Customers, Products and Orders... I will asume that an order can have one or more products.
Then, design your tables (I will use MySQL style for the code):
Your customers catalog:
create table tbl_customers (
customerId int not null primary key,
customerName varchar(100),
customerAdress varchar(200)
);
Your products catalog:
create table tbl_products (
productNumber int not null primary key,
productName varchar(100),
);
Your orders catalog:
create table tbl_orders (
orderId int not null primary key,
orderDate date,
customerId int unsigned not null
);
For each order, you will need to know how many 'units' of which products you will be ordering:
create table tbl_orders_products (
orderProductId int not null primary key,
orderId int not null,
productNumber int not null,
units int,
);
After this, you will populate your tables with your data, and then you can perform whichever query fits you.
A few notes:
tbl_orders is related with tbl_customers... your customer's data will have to be inserted in tbl_customers before he can place an order.
Before you insert the order's details, you will need to create the order
Before you insert the order's details, you will need to populate tbl_products
This is just a way to solve it.
Hope this helps you
Now, if you want to move to this model, you have some work to do:
Populate your products catalog: insert into tbl_products values (1,'productA'), (2, 'productB'), ...
Populate your customers catalog
Then you can start placing your orders. I'll asume that you have the following customers:
customerId | customerName | customerAdress
---------------------------------------------
1 | John Doe | 31 elm street
2 | Jane Doe | 1223 park street
... and products:
productNumber | productName
------------------------------
1000 | Pencil
2000 | Paper clip
3000 | Bottled water
Now, placing an order is a two-step process: first, create the order record, and then insert the order details:
The order (Customer John Doe): insert into tbl_orders values (1, '2012-10-17', 1);
The order details (one pencil, ten paper clips): insert into tbl_orders_products values (1, 1, 1000, 1), (2, 1, 2000, 10);
Now, to select the customer for order seven (as stated in your question), you can use the following query:
select c.*
from tbl_customers as c
inner join tbl_orders as o on c.customerId = o.customerId
where o.orderId = 7;
This is just a start point. You should look for good books or online tutorials (w3 tutorials can be a good online 'place' to start).
Although I don't quite like MS Access, it's a good program to learn the basics of sql, and there're a lot of books and learning resources for it. Note: I don't like Access, and I don't mean to advertise it, but it might be a good learning tool.
First you need to normalise, there 's a lot of stuff around that, but loads of tutorials that try and take some common sense and make it really obscure
Looking at your column names I see three tables
Customers(CustomerID, CustomerName, CustomerAddress)
CustomerOrders(OrderID, CustomerID, SellDate, ProductNumber) Try not to name your tables and columns and such the same as Sql keywords.
Products(ProductNumber, ProductDescription)
Normalisation says things like, you should be able to uniquely identify any records in the table, you had that with OrderId. When I split the tables up I added CustomerID, because you could have more than one customer with the same name.
Another simple rule is in your structure, if you had more than one order for a customer, you would be storing their name and address more than once, which is wasteful, but the real problem, is what if that customer changes address? How do you find which rows to change, you could do Where name = "Fred" and Address = "Here", but you don't know if you have more than one customer called Fred with an address of Here.
So you first query would be a join
Select Customers.CustomerName,Customers.CustomerAddress From Customers
Inner join CustomerOrders On Customers.CustomerID = CustomerOrders.CustomerID
Where CustomerOrders.OrderID = 7
Or if you want to skip past learning joins for now, you could do it with two queries
Select CustomerID From CustomerOrders Where OrderID = 7
then
Select CustomerName,CustomerAddress From Customers Where CustomerID = ?
You should be using joins, but you might find sub-query a little easier to get your head round. You can do both queries at once with
Select CustomerID From CustomerOrders
Where CustomerID In (Select CustomerID From CustomerOrders Where OrderID = 7)
Don't know far you've got with sql table creation, but Primary and Foreign keys is two things to look at. That will let you put some rules in the database. A primary Key on CustomerOrders will stop you having two orders with the same ID, which would be bad.
A foreign Key would stop you creating a CustomerOrder for a customer that did not exist, and one to products for a product that doesn't.
Assuming you went down that route and you were looking to write an application to order things.
You'd probably have a function to maintain Customers which would add them with something like
Insert Into Customers(CustomerID,CustomerName,CustomerAddress) Values(1,'Fred Bloggs','England')
And one For Products
Insert Into Products(ProductNumber,ProductDescription) Values(1,'A thingamabob')
Then you'd choose a customer, so you have it's id, select a product so you have it's number, so you don't need to mess with CustomerName, CustomerAddress or ProductDescription
and
Insert Into CustomerOrders(OrderID,CustomerID,ProductNumber,SellDate) Values(1,1,1,'20121017')
Note the date format, if you are going to pass dates as strings to sql, (another topic this) do them in YYYYMMDD, when you get them back out with a select, you'll get them in the format your machine/database is set up for which in your case seems to be mm/dd/yyyy. The problem is I deduced that because I know there are only twelve months in the year. (One of the things that makes me a senior dev :) If your example selldate had been 1/5/2012, I'd have read that as the 1st May, because I'm configured for English. Avoid that ambiguity at all costs it will reach out and hurt you on a regular basis.
PS the way you did it 1/15/2012 would be treated as a mathematical expression as in 1 divided by 15 ...
So the reason you couldn't write a join is basically you only had one table. Join is join one table to another. Well actually it's a bit more complex than that, but that's a good way past where you are in the learning curve.
As for moving the data, be quicker to start again I should think. Unlikely you have created two different customers with the same name, but the queries to move the data, would have to take into account that you could have.
To move the data, assuming CustomerID is an Identity (Autonumber) column
Something like
Insert into Customers(CustomerName,CustomerAddress)
Select Distinct CustomerName,CustomerAddress From [Order]
Would do the job for Customers.
Then for products
Insert into Products(ProductDescription)
Select Distinct ProductDescription From [Order]
Then
Insert into CustomerOrders(OrderID,CustomerID,ProductNumber,SellDate)
Select old.OrderID,c.CustomerID,p.ProductNumber,old.SellDate
From [Order] old
Inner Join Products p On p.ProductDesription = old.ProductDescription
Inner Join Customers c On c.CustomerName = old.CustomerName And c.CustomerAddress = old.CustomerAddress
might do CustomerOrders I think
A simple tip. When modelling a data solution, try to write down simple sentences that describe the scenario. For example (ok, it is just a basic one):
An order is made up of many order lines
An order line refers a product
A customer create many orders
Here, the nouns describe the entities of your scenario. Then, for each entity, try to describe its property:
An order is characterized by a unique serial number, a date, a total. It refers a customer.
An order line refers to a product, and is characterized by a quantity, a unit price, a sub total
A customer....
An so on.
Well, in your model you roughly have to create a table for each entity. The table fields are taken from the property of each entity. For each field remeber to define the proper data type.
Ok, this is NOT a modelling tutorial, but it is a starting point, just to approach the solution.

Establishing a one to many relationship between 2 tables

I am building a database which consists of a
table of category, customer table, and table of product which fetches information from categories.
Now I need a new table for sale which consists of customerID, date, productID. My problem is
the customer may buy many products. how can I make the relation between them in SQL Server 2008?
Customer {id, name, ...}
Product {id, name, ...}
Sale {product_id, customer_id, order_id, qty, ...}
Order {id, date, ...}
Just add a order table, the order table will keep reference to the products in the order.
Your drawing commented on in #orn's answer only makes sense if each sale can only involve one product.
Mr Fliim put you on the right track to deal with multiple products in one sale.