###BeginCaseStudy###
Case Study 2
Contoso Ltd
Overview
Application Overview
Contoso, Ltd., is the developer of an enterprise resource planning (ERP) application.
Contoso is designing a new version of the ERP application. The previous version of the ERP
application used SQL Server 2008 R2. The new version will use SQL Server 2014.
The ERP application relies on an import process to load supplier data. The import process
updates thousands of rows simultaneously, requires exclusive access to the database, and runs daily.
You receive several support calls reporting unexpected behavior in the ERP application.
After analyzing the calls, you conclude that users made changes directly to the tables in the
database.
Tables
The current database schema contains a table named OrderDetails. The OrderDetails
table contains information about the items sold for each purchase order. OrderDetails
stores the product ID, quantities, and discounts applied to each product in a purchase
order. The product price is stored in a table named Products.
The Products table was defined by using the SQL_Latin1_General_CPl_CI_AS collation. A
column named ProductName was created by using the varchar data type.
The database contains a table named Orders. Orders contains all of the purchase orders from
the last 12 months. Purchase orders that are older than 12 months are stored in a table named OrdersOld.
Stored Procedures
The current version of the database contains stored procedures that change two tables. The
following shows the relevant portions of the two stored procedures:
Customer Problems
Installation Issues
The current version of the ERP application requires that several SQL Server logins be set up
to function correctly. Most customers set up the ERP application in multiple locations and
must create logins multiple times.
Index Fragmentation Issues
Customers discover that clustered indexes often are fragmented. To resolve this issue, the
customers defragment the indexes more frequently.
All of the tables affected by fragmentation have the following columns that are used as the
clustered index key:
Backup Issues
Customers who have large amounts of historical purchase order data report that backup time
is unacceptable.
Search Issues
Users report that when they search product names, the search results exclude product names
that contain accents, unless the search string includes the accent.
Missing Data Issues
Customers report that when they make a price change in the Products table, they cannot
retrieve the price that the item was sold for in previous orders.
Query Performance Issues
Customers report that query performance degrades very quickly. Additionally, the customers
report that users cannot run queries when SQL Server runs maintenance tasks.
Import Issues
During the monthly import process, database administrators receive many supports call from
users who report that they cannot access the supplier data. The database administrators want
to reduce the amount of time required to import the data.
Design Requirements
File Storage Requirements
The ERP database stores scanned documents that are larger than 2 MB. These files must only
be accessed through the ERP application. File access must have the best possible read and
write performance.
Data Recovery Requirements
If the import process fails, the database must be returned to its prior state immediately.
Security Requirements
You must provide users with the ability to execute functions within the ERP application,
without having direct access to the underlying tables.
Concurrency Requirements
You must reduce the likelihood of deadlocks occurring when Sales.Proc1 and Sales.Proc2 execute.
###EndCaseStudy###
You need to recommend a solution that resolves the missing data issue. The solution must
minimize the amount of development effort.
What should you recommend?
A.
Denormalize the Products table.
B.
Denormalize the OrderDetails table.
C.
Normalize the OrderDetails table.
D.
Normalize the Products table.
Explanation:
* Scenario:
/ Missing Data Issues
Customers report that when they make a price change in the Products table, they cannot
retrieve the price that the item was sold for in previous orders.
/ The current database schema contains a table named OrderDetails. The OrderDetails table
contains information about the items sold for each purchase order. OrderDetails stores the
product ID, quantities, and discounts applied to each product in a purchase order. The
product price is stored in a table named Products.
I don’t believe that D is correct. You can’t normalize the products table any more, there is not any extra repeated data. In this case, denormalizing the OrdersDetail table by adding a price column seems like the logical answer.
There are further 2 tables of order so i dont think it wise to play with that table
The product price is stored in a table named Products.
Normalize the Products table.
mayby add column to Products table, like date…
Date of what?!
Date that you set the price. Just think that on each date the price may be changed. We have Order date, so we can retrieve the price of each order on the ordered Date.
Put the price on orderdetails. This is denormalization.
You are right the Product Details Table have the discount without the price so we want to Demoralize the Product Details table by adding the Price column to it that we can calculate the discount on each product
Thanks
You meant OrderDetails table?! It is OrderDetails table that needs to be denormalized by adding ‘Old Price’, ‘New price’, and ‘Discount’ columns to it.
when customers update the products table to change the price and want to keep the historical information of the price there should be a price table referenzed to the product table. like
ID(PK) ProductID(FK) validfrom validtill price
this is a denormalization of products table
Well is it Normalize of De-Normalize. Because we are removing an expected duplication from Product table. Which comes in Normalization.
You are right the product table is normalized Already and has Product-ID, ..,Price so it must has old price(Before discount and New price after discount) so the is demoralization of the product table
Not the Products table. You meant the OrderDetails table? Because, that’s where you have the Discount.
+1, adding time stamp is the only way to check historical price changes and this is what this question asking for.
Denormalize orderdetails
D is correct
Please explain!!
we create a potent duplicate data on orderdetails if we add price.
If the price is never changed the price would be identical for the products.price and the orderdetail.price table.
This is called denormalized, because data is duplicated.
If the price in product table changes, the price in orderdetails would be non redundant. But as long its identical its redundant and so called denormalized.
In effect: You have to add the column price to orderdetails, which is a denormalization.
B
How about create a new table – ProductPrice?
eg:
ORIG Design: Product(ProductID, Price)
NEW Design: Product(ProductID ) ProductPrice(ProductID, Date, Price)
Would above means “Normalize the Products table”?
This one could IMHO go either way.
D: Normalize the Products table…
You could add an additional table to store product price. This would have a timestamp (probably), the product pk and likely its own pk. OrderDetail rows could reference the ProductPrice PK rather than the product (and from there the product). Alternatively it could use the date to determine the price though that’s going to be even more expensive to calculate. All very messy I reckon and way more expensive to query for very little real world gain.
B: Denormalize the OrderDetails table…
Very simple and much more likely the way that I’d expect it to be done in a real world OLTP application. Store the product price at the time of the sale on the order line. No muss, no fuss. 🙂
I’m going with B:
Agree, the solution must minimize the amount of development effort.
In the real world, you would add the purchase price into the order table. Everytime you update a product with a new price, you don’t want to add another product to the product table. Another vague Microsoft question. you want to denormalize the product table
CREATE TABLE Sales.Products (
ProductID bigint IDENTITY(1,1) NOT NULL PRIMARY KEY,
ProductName varchar(200) NOT NULL
);
GO
CREATE TABLE Sales.ProductPrices (
ProductID bigint NOT NULL,
PriceDate datetime NOT NULL DEFAULT (GETDATE()),
PriceValue money NOT NULL
);
GO
ALTER TABLE Sales.ProductPrices
ADD CONSTRAINT PK_Sales_ProductPrices
PRIMARY KEY (ProductID, PriceDate);
GO
ALTER TABLE Sales.ProductPrices
ADD CONSTRAINT FK_Sales_ProductPrices_Sales_Products
FOREIGN KEY (ProductID)
REFERENCES Sales.Products(ProductID);
GO
CREATE VIEW Sales.OrderDetailsReport
AS
WITH tblProductPrices AS (
SELECT
[PP].ProductID,
[PP].PriceDate AS [StartPriceDate],
LEAD([PP].PriceDate, 1, ‘9999-12-31 23:59:59’) OVER(PARTITION BY [PP].ProductID ORDER BY [PP].ProductID ASC, [PP].PriceDate ASC) AS [EndPriceDate]
FROM
Sales.ProductPrices [PP]
),
tblOrdersDetails AS (
SELECT
[OD].OrderID,
[O].OrderDate,
[P].ProductID,
[P].ProductName,
[PP].PriceValue AS [Price]
FROM
Sales.OrderDetails [OD]
INNER JOIN
Sales.Orders [O]
ON
[OD].OrderID = [O].OrderID
INNER JOIN
Sales.Products [P]
ON
[OD].ProductID = [P].ProductID
INNER JOIN
tblProductPrices [PP]
ON
[P].ProductID = [PP].ProductID
AND [OD].OrderDate BETWEEN [PP].StartPriceDate AND [PP].EndPriceDate
)
SELECT OrderID, OrderDate, ProductID, ProductName, Price FROM tblOrdersDetails;
GO
–And if you want a current product price.
CREATE VIEW Sales.CurrntPrice
AS
WITH tblMaxDate AS (
SELECT
[PP].ProductID,
MAX([PP].PriceDate) AS [PriceDate]
FROM
Sales.ProductPrices [PP]
GROUP BY
[PP].ProductID
),
tblOutput AS (
SELECT
[PP].ProductID,
[PP].PriceValue AS [Price]
FROM
Sales.ProductPrices [PP]
INNER JOIN
tblMaxDate [MD]
ON
[PP].ProductID = [MD].ProductID
AND [PP].PriceDate = [MD].PriceDate
)
SELECT ProductID, Price FROM tblOutput;
GO
Means, “D” is right.