Please start any new threads on our new
site at https://forums.sqlteam.com. We've got lots of great SQL Server
experts to answer whatever question you can come up with.
| Author |
Topic |
|
MikeB
Constraint Violating Yak Guru
387 Posts |
Posted - 2004-04-19 : 12:47:45
|
| I am trying to develop an estimation software package and I am a little confused about the table structure required to provide price list(s) for the takeoff portion of the software. There are many different item types to be included in the takeoff and each has a unique process that determines the prices.Example, the main product is concrete components, so the price of a component is influenced by the price of its aggregates. Another product is field hardware and cast in hardware which are steel assemblies either used on the construction site or cast into the concrete components. The price of hardware is influenced by the price of its components (Steel flat bar, studded anchors, rebar, etc...)Also, the estimate will include items for shipping the product, erection of the product, finishing etc....What I am wondering is....should there be a price list (table) for each item category, or should there be single table for all items.Some items require information that other items do not, for example, shipping rate would require a company and location, a product rate would not.I get so confused with this because there is so much. I create a table structure that I think will work but once I get into it, I learn that it does not....Any thoughts? How would you build this table structure?Mike B |
|
|
DustinMichaels
Constraint Violating Yak Guru
464 Posts |
Posted - 2004-04-19 : 13:51:57
|
| I'm not an expert in database design but you may want to use the concept of entity sub types.To do this make a common table which will share all of the attributes for the different products.tbProductintProductID PKtbName...Then you can use 1 to 1 relationships with the tbProduct table to create your entity sub types.For example for the concrete component products you could have a table like this.tbConcreteComponentintProductID PK FK To the tbProduct table....tbConcreteComponentPartintConcreteComponentPart PKintProductID FK to tbConcreteCompoent table.mnyPrice...Then for each other type of entity just extend the idea that I used in the tbConcreteComponent table. However, I'm still a newb at database design so you'll still want to get the opinions of the experts on this site.Good luck.Dustin Michaels |
 |
|
|
MikeB
Constraint Violating Yak Guru
387 Posts |
Posted - 2004-04-19 : 14:06:34
|
quote: Originally posted by DustinMichaels I'm not an expert in database design but you may want to use the concept of entity sub types.To do this make a common table which will share all of the attributes for the different products.tbProductintProductID PKtbName...Then you can use 1 to 1 relationships with the tbProduct table to create your entity sub types.For example for the concrete component products you could have a table like this.tbConcreteComponentintProductID PK FK To the tbProduct table....tbConcreteComponentPartintConcreteComponentPart PKintProductID FK to tbConcreteCompoent table.mnyPrice...Then for each other type of entity just extend the idea that I used in the tbConcreteComponent table. However, I'm still a newb at database design so you'll still want to get the opinions of the experts on this site.Good luck.Dustin Michaels
Good idea, but, if I was to do this, how do I know what table to link to ... or is that a concern since the ProductID is the primary key on the ConcreteComponent table?Would I LEFT JOIN to all tables on the ProductID when I query the tables?Mike B |
 |
|
|
DustinMichaels
Constraint Violating Yak Guru
464 Posts |
Posted - 2004-04-19 : 14:23:29
|
| I think LEFT OUTER JOIN could work in this situation, but your select queries would be very complicated (probably have to use alot of case statements).Perhaps you could create a view that would be the union of all your entity sub types. In this example I'll just assume that you have another entity sub type called tbShippedProduct which should include the shipping cost with the price.for exampleCREATE VIEW viewAllProductsAS--UNION together all of the entity sub types.SELECT tbProduct.intProductID, tbProduct.charName, SUM(tbConcreteComponentPart.mnyPrice) AS Price, 'Concrete Component' AS ProductTypeFROM tbProduct INNER JOIN tbConcrete tbConcreteComponent ON(tbProduct.intProductID = tbConcreteComponent.intProductID) INNER JOINtbConcreteComponentPart ON (tbConcreteComponent.intProductID = tbConcreteComponentPart.intProductID)GROUP BY tbProduct.intProductIDUNION ALLSELECT tbProduct.intProductID, tbProduct.charName,tbShippedProduct.mnyShippingPrice + tbShippedProduct.mnyPrice AS Price,'Shipped Product' AS ProductTypeFROM tbProduct INNER JOIN tbShippedProduct ON (tbProduct.intProductID = tbShippedProduct.intProductID)UNION ALL ...continue with other types.Then for example, you want to do a query on the concrete products you could do the following.SELECT viewAllProducts.intProductID, viewAllProducts.charName, viewAllProducts.PriceFROM viewAllProductsWHERE viewAllProducts.ProductType = 'Concrete Component' This method may be slow though. There are probably some other alternatives that are much more efficient to this solution.Good luck.Dustin Michaels |
 |
|
|
MikeB
Constraint Violating Yak Guru
387 Posts |
Posted - 2004-04-19 : 14:53:09
|
quote: Originally posted by DustinMichaels I think LEFT OUTER JOIN could work in this situation, but your UNION ALL.............Dustin Michaels
I just did the DDL with this table structure, and honestly, I am not sure it is the right approach. Check out the DDL and see what you think?USE NORTHWINDGOCREATE TABLE tbProduct (ProductID INT IDENTITY (1,1) NOT NULL,Product VARCHAR (100) NOT NULL)GOALTER TABLE tbProduct ADD CONSTRAINT tbProduct_pk PRIMARY KEY (ProductID)GOCREATE TABLE tbProduct1 (fkProductID INT NOT NULL,Var1 FLOAT NOT NULL,Var2 FLOAT NOT NULL,)GOALTER TABLE tbProduct1ADD CONSTRAINT tbProduct1_pk PRIMARY KEY (fkProductID)GOALTER TABLE tbProduct1ADD CONSTRAINT tbProduct1_fk FOREIGN KEY (fkProductID)REFERENCES tbProduct (ProductID)GOCREATE TABLE tbProduct2 (fkProductID INT NOT NULL,Var1 FLOAT NOT NULL,Var2 FLOAT NOT NULL,Var3 FLOAT NOT NULL,)ALTER TABLE tbProduct2ADD CONSTRAINT tbProduct2_pk PRIMARY KEY (fkProductID)GOALTER TABLE tbProduct2ADD CONSTRAINT tbProduct2_fk FOREIGN KEY (fkProductID)REFERENCES tbProduct (ProductID)GOINSERT INTO tbProduct (Product)SELECT 'First Product'GOdeclare @iProductID intSELECT @iProductID = @@IdentityINSERT INTO tbProduct1 (fkProductID, Var1, Var2)SELECT @iProductID, 10, 10GOINSERT INTO tbProduct (Product)SELECT 'Second product'GOdeclare @iProductID intSELECT @iProductID = @@IdentityINSERT INTO tbProduct2 (fkProductID, Var1, Var2, Var3)SELECT @iProductID, 10, 10, 10GOSELECT p.ProductID, p.Product, One.*, Two.* FROM tbProduct AS p LEFT JOIN tbProduct1 AS OneON p.ProductID = One.fkProductIDLEFT JOIN tbProduct2 AS TwoON p.ProductID = Two.fkProductIDWHERE p.ProductID = 1GODROP TABLE tbProduct1GODROP TABLE tbProduct2GODROP TABLE tbProductGO There just doesn't seem to be any good way to direct the data flow for inserts, deletes, etc....Also, look what happens when I do a left join. You will get the fields for all products but they will be NULL (as they should be but..)Mike B |
 |
|
|
DustinMichaels
Constraint Violating Yak Guru
464 Posts |
Posted - 2004-04-19 : 15:48:44
|
| If you don't want to go with the entity sub type method you could just make one table and use alot of case statements in your select commands. Also you'll probably have to use corralated sub queries.tbProductintProductID PKcharNameintProductTypeID FKtbProductTypeintProductTypeID PKcharNametbConcreteComponentPartintConcreteComponentPartID PKintProductID FK to tbProduct.mnyPricetbShippingProductintProductID PK and FK to tbProductmnyPricemnyPriceToShipThen your select statement could look like this. SELECT tbProduct.intProductID, tbProduct.charName,CASE WHEN tbProductType.charName = 'Concrete Component' THEN (SELECT SUM(tbConcreteComponentPart.mnyPrice) FROM tbConcreteComponentPart WHERE tbConcreteComponentPart.intProductID = tbProduct.intProductID) WHEN tbProductType.charName = 'Shipping' THEN(SELECT tbShippingProduct.mnyPrice + tbShippingProduct.mnyPriceToShip FROM tbShippingProduct WHERE tbShippingProduct.intProductID = tbProduct.intProductID)WHEN ...other types of productsEND AS PriceFROM tbProductEither way you choose I think it is going to be very complicated to implement.Dustin Michaels |
 |
|
|
MichaelP
Jedi Yak
2489 Posts |
Posted - 2004-04-19 : 16:22:39
|
| Here's another approach to this problem. Come up with a rules engine to handle this.Example:You add "Strong Concrete" and "Rebar" to a project.Each one of those entity's has a set of rules that calulates its' costs. A "rule" would be a stored proc that takes some standard set of params (probably just the entity ID and maybe a customerID for discounts etc) and the rule would run all the complicated logic to handle shipping, cost of all the materials that make up the entity etc. The Rule's final output will be total cost for that one entity.You add these two Entity's into some sort of rules processing queue, and you have your rules engine look at each row and "run the rules" to come up with a cost for each of those items. I think you'll still have lots of very different tables to setup and populate for all the different types of components. Did that make sense?Michael<Yoda>Use the Search page you must. Find the answer you will.</Yoda> |
 |
|
|
MikeB
Constraint Violating Yak Guru
387 Posts |
Posted - 2004-04-20 : 08:48:25
|
quote: Originally posted by DustinMichaels..........................tbProductintProductID PKtbName...
Is tbName supposed to be the name of the product table to look for when manipulating data?I actually thought of doing this for some other things but alot of people seemed to froun upon the idea!What does everyone think of doing this?Mike B |
 |
|
|
DustinMichaels
Constraint Violating Yak Guru
464 Posts |
Posted - 2004-04-20 : 09:15:06
|
quote: Originally posted by MikeB
quote: Originally posted by DustinMichaels..........................tbProductintProductID PKtbName...
Is tbName supposed to be the name of the product table to look for when manipulating data?I actually thought of doing this for some other things but alot of people seemed to froun upon the idea!What does everyone think of doing this?Mike B
I just messed up when I wrote down tbName. I meant to say charName. The name should be a column in the tbProduct table not another separate table. But I guess it could be possible to have dynamic table's in which the column tbName could point to. I've never done this before though.Dustin Michaels |
 |
|
|
MikeB
Constraint Violating Yak Guru
387 Posts |
Posted - 2004-04-21 : 16:51:53
|
quote: Originally posted by DustinMichaels
quote: Originally posted by MikeB
quote: Originally posted by DustinMichaels..........................tbProductintProductID PKtbName...
Is tbName supposed to be the name of the product table to look for when manipulating data?I actually thought of doing this for some other things but alot of people seemed to froun upon the idea!What does everyone think of doing this?Mike B
I just messed up when I wrote down tbName. I meant to say charName. The name should be a column in the tbProduct table not another separate table. But I guess it could be possible to have dynamic table's in which the column tbName could point to. I've never done this before though.Dustin Michaels
Dustin, I have looked into this sub-type / super type rationalle and I am still a little hesitant but a little more confortable then with the alternatives. Thanks for the suggestions.Mike B |
 |
|
|
|
|
|
|
|