Mapping a table to lots of other tables? - sql

I have a website I develop that is structured a little like stackoverflow. I have a Posts table and a PostImages table in the database. The PostImages table looks like this:
PostImageId PK
PostId FK
Uri
MimeType
So posts can have lots of images associated with them.
I now have the requirement that other places on the site should have images: Users should be able to have images on their profile, Categories should be able to have images, and Addresses should be able to have images.
It seems best to only have a single Images table in my database. How should I model this? I could have a single table like this:
ImageId PK
PostId FK
CategoryId FK
AddressId FK
UserId FK
Uri
MimeType
I could have a single images table, then extra tables for each kind of object:
PostImageId PK FK
PostId FK
CategoryImageId PK FK
CategoryId FK
(where the PK of each item is also FK to an image from the Images table)
There are some other strategies, too: for instance, I could have a ___Images table for each type, and no shared Images table. I could have a many-to-many mapping table for each, and perhaps there are some other solutions I haven't thought of.
What is best? I don't know that much about database design - which will be the most flexible and easiest to use?

In real life projects, Database is designed regarding to the cost of accessibility of data. You mentioned two ways of designing your tables. Both are correct. If you put all your fields in one table there will be data redundancy. If you make two tables there is no problem.
But you have to keep in mind that joining two tables will cost more. So while fetching data from your server, this may make your page slow (If concurrently a lot of users try at the same time).
On the other hand, if you put it in one field, it will take more memory in database but less cost in data fetching. The choice is yours.

I went with the second choice. I have an Images table:
Images
ImageId PK
Name
Uri
Width
Height
MimeType
and several mapping tables:
PostImages
PostImageId PK FK
PostId FK
CategoryImages
CategoryImageId PK FK
CategoryId FK
I prefer this solution as I can add more mapping tables without changing the Images table. It's easier to maintain. Also, it allows the Images table to be more semantic as it only contains data about images.
The cost of the join isn't a big problem as I only return a small number of images in any query. However, I haven't tested the relative speed of the two methods.

Related

Proper Structure

I am building a webforms app using a 3 tier model and ado.net. (UI code behind) (middle tier 'classes') (DAL). Although EF would be a good fit, I would like to avoid it for this project as I am not familiar with it.
My database has a few tables and they have foreign key relationships between the tables. The app will have simple display, add, update, delete functions for each table.
I have created a class for each table that outlines the properties which correspond to each database column. So my question is how to handle the relationships between the tables, here is a simple example-
Table 'cars'
CarID
OwnerID
ColorID
Make
Model
Table 'Owners'
OwnerID
Fname
Lname
Table 'Colors'
ColorID
ColorName
On the Cars 'management' page -
The Owners and color tables should be represented as dropdownlists.
Do I load/bind the 'Owners' and 'Colors' lists with separate ado queries and simply save the 'IDs' of each field using the 'Cars' class or is there a way to tie these together, it seams there would be a more efficient way rather then making multiple database dips to pull the lists.
Any thoughts or comments welcome and appreciated.

How should I set up database tables for this order situation

I'm building a web application for a printing company and am trying to determine the best design for my database.
I have an orders table. Each order has many proofs. However, there are two different kinds of proofs: electronic proofs and physical proofs. Furthermore, if its an electronic proof, I need to store the image source, and if its a physical proof, i need to store a tracking number.
Every proof has many comments associated with it.
It would be nice if i could just have one proofs table, and one comments table, but what is the best way to keep track of the image source and tracking number based on the proof type?
I've considered creating separate tables for electronic_proofs and physical_proofs, but that would require making a separate electronic_proof_comments table and physical_proof_comments table.
The other option would be to have a single proofs table, in which case I could then have a single comments table. However, as I see it, that would require three support tables, proof_types, image_sources, and tracking_numbers.
Any thoughts on the best way, or an even better way of solving this problem?
As mentioned in another answer, you only need one table and would simply leave one of the fields blank, depending on the type. However, the difference in my answer would be to relate the order details to the proof rather than the proof to the order details (or order item in their example). Doing it this way allows you to have multiple proofs per order detail.
This is how I would set it up if I were you:
ORDERS
OrderID (PK)
CustomerID (FK)
Etc...
ORDERDETAILS
OrderDetailsID (PK)
OrderID (FK)
ProductID? (FK)
Etc...
PROOFS
ProofID (PK)
OrderDetailsID (FK)
ProofType
ImagePath (just path, not image)
TrackingNumber
Etc...
COMMENTS
CommentID (PK)
ProofID (FK)
Comment
Etc...
It would probably also be wise to break ProofType into it's own table, but will work without. If you were to do that, you'd create a ProofType table and change the "ProofType" field in the "Proofs" table to a foreign key referencing the "ProofTypeID" field in the new "ProofType" table.
Hope this helps! Good Luck!
I agree with #Ricketts (+1). The tricky part is whether to have columns ImagePath and TrackingNumber in the Proof table, or to normalize them out into separate tables. (Normalize, because they don't depend on the primary key, they depend on the primary key + the proof type column.) If these are the only two columns that are proof-type-specific, then you're probably ok storing them in the single table... but that ImagePath makes me nervous, particularly if its not an image but an actual sizable chunk of binary data. It might make sense for a number of reasons to store that data separately in its own table, but not move TrackingNumber out as well.
Other considerations: what's the ratio between proof types? How is performance likely to work (particularly if there's a BLOB involved in your data requests?) You have to weigh and perhaps test these considerations before making your final decision.
I would expect that proof type is just an attribute of the item, as is the tracking number and image source, correct?
It's similar to a situation where some items may come in sizes, but some don't - you just don't populate the attributes that don't matter for that specific type of item.
Also, note that with two different "proof" tables, your order line item table now has to deal with two different entities.
Something like this should be doable for basic use...
ORDERS
Order ID (PK)
ORDER ITEM
Order Item ID (PK)
Order ID (FK)
Proof ID (FK)
PROOF
Proof ID (PK)
Proof Name
Proof Type
Tracking Number
Image Source
COMMENTS
Comment ID (PK)
Proof ID (FK)
Comment Text
You can create lookup tables for proof type, tracking number, and image source if necessary. It really depends on how far you want to go to match reality to relational theory.

Table referenced by other tables having different PKs

I would like to create a table called "NOTES". I was thinking this table would contain a "table_name" VARCHAR(100) which indicates what table put in the note, a "key" or multiple "key" columns representing the primary key values of the table that this note applies to and a "note" field VARCHAR(MAX). When other tables use this table they would supply THEIR primary key(s) and their "table_name" and get all the notes associated with the primary key(s) they supplied. The problem is that other tables might have 1, 2 or more PKs so I am looking for ideas on how I can design this...
What you're suggesting sounds a little convoluted to me. I would suggest something like this.
Notes
------
Id - PK
NoteTypeId - FK to NoteTypes.Id
NoteContent
NoteTypes
----------
Id - PK
Description - This could replace the "table_name" column you suggested
SomeOtherTable
--------------
Id - PK
...
Other Columns
...
NoteId - FK to Notes.Id
This would allow you to keep your data better normalized, but still get the relationships between data that you want. Note that this assumes a 1:1 relationship between rows in your other tables and Notes. If that relationship will be many to one, you'll need a cross table.
Have a look at this thread about database normalization
What is Normalisation (or Normalization)?
Additionally, you can check this resource to learn more about foreign keys
http://www.w3schools.com/sql/sql_foreignkey.asp
Instead of putting the other table name's and primary key's in this table, have the primary key of the NOTES table be NoteId. Create an FK in each other table that will make a note, and store the corresponding NoteId's in the other tables. Then you can simply join on NoteId from all of these other tables to the NOTES table.
As I understand your problem, you're attempting to "abstract" the auditing of multiple tables in a way that you might abstract a class in OOP.
While it's a great OOP design principle, it falls flat in databases for multiple reasons. Perhaps the largest single reason is that if you cannot envision it, neither will someone (even you) looking at it later have an easy time reassembling the data. Smaller that that though, is that while you tend to think of a table as a container and thus similar to an object, in reality they are implemented instances of this hypothetical container you are trying to put together and operate better if you treat them as such. By creating an audit table specific to a table or a subset of tables that share structural similarity and data similarity, you increase the performance of your database and you won't run in to strange trigger or select related issues later.
And you can't envision it not because you're not good at what you're doing, but rather, the structure is not conducive to database logging.
Instead, I would recommend that you create separate logging tables that manage the auditing of each table you want to audit or log. In fact, some fast google searches show many scripts already written to do much of this tasking for you: Example of one such search
You should create these individual tables and then if you want to be able to report on multiple table or even all tables at once, you can create a stored procedure (if you want to make queries based on criterion) or a view with an included SELECT statement that JOINs and/or UNIONs the tables you are interested in - in a fashion that makes sense to the report type. You'll still have to write new objects in to the view, but even with your original table design, you'd have to account for that.

Store forum subcategories in the same table or in a separate table

I'd like to hear opinions on if it is better to keep forum categories and subcategories in the same table or in two separate tables...
Let's say you have a table ForumCategories. By adding a colum ParentId referencing the PK Id in the same table you could easily keep both the main categories and subcategories in the same table.
Alternatively, you could create a separate table ForumSubCategories and make the Id on that table a FK referencing PK Id column of the ForumCategories table.
Both solutions would work but what are the pros and cons of each solution?
Obviously, this is a more generic question that can apply to many other scenarios I just couldn't come up with a better phrasing in a hurry...
I can't think of any benefits of using 2 tables. Using 2 tables is going to constrain you to a 2 level tree. If you look at things as objects, then subcategories really are just category object. So put them in the same table. The 1 table structure will be simpler to design around and develop queries for.
If you know for sure that your forums will have only 2 levels of categories, then having 2 tables is reasonable.
Though storing categories in one table with foreign key to itself, basically, allows you store a tree of categories with virutally unlimited levels.
If they are the same entity (Category), you can link to itself. The parent would have a null for the parent ID or it could be linked to itself. This limits you to only one level unless you have a second table to handle the many-to-many possible relationships.
They must have the same fields or you're going to have unecessary fields for one or the other type. A separate table is why you would do this because they're not the same.
This is typical for an employee table. The supervisor is another employee record.

Owner ID type database fields

Suppose you have these tables: RestaurantChains, Restaurants, MenuItems - with the obvious relations between them. Now, you have tables Comments and Ratings, which store the customer comments/ratings about chains, restaurants and menu items. What would be the best way to link these tables? The obvious solutions could be:
Use columns OwnerType and OwnerID in the tables Comments and Ratings, but now I can't add foreign keys to link comments/ratings with the objects they are ment for
Create separate tables of Comments and Ratings for each table, e.g. MenuItemRatings, MenuItemComments etc. This solution has the advantage that all the correct foreign keys are present and has the obvious disadavantage of having lots and lots of tables with basically the same structure.
So, which solution works better? Or is there even a better solution that I don't know about?
Since comments about a menu item are different from comments about a restaurant (even if they happen to share the same structure) I would put them in separate tables and have the appropriate FKs to enforce some data integrity in your database.
I don't know why there is an aversion to having more tables in your database. Unless you're going from 50 tables to 50,000 tables you're not going to see a performance problem due to large catalog tables (and having more, smaller tables in this case should actually give you better performance). I would also tend to think that it would be a lot clearer to understand when dealing with tables called "Menu_Item_Comments" and "Restaurant_Comments" than it would to deal with a table called "Comments" and not knowing what exactly is really in it just by the name of it.
How about this alt text http://www.freeimagehosting.net/uploads/8241ff5c76.png
Have a single Comments/Rating table for all the objects and dont use automatically generated foreign keys. The key in the ratings table eg RatingID can be placed in a field in Restaurant, Chain, Menuitems table and they can all point to the same table, they are still foreign keys.
If you need to know in reverse what object the review relates to you would need to have a field specifying the type of review it was, but that should be all.
Use a single table for comments and use GUID's as primary keys for your entites.
Then you can select comments without even knowing beforehand where they belong to:
SELECT CommentText
FROM Comments c, Restaurants r
WHERE c.Source = r.Id
SELECT CommentText
FROM Comments c, Chains ch
WHERE c.Source = ch.Id
etc.
You can't use foreign keys for comments, of course, but it's not that comments cannot live without foreign keys.
You may clean orphaned comments in triggers but there's nothing bad if some of them are left.
You amy also create a global Entity table (with a single GUID column), make your Chains, Restaurants, MenuItems and Comments refer to that table with a FOREING KEY ON DELETE CASCADE, and when DELETE'ing, say, a restaurant, delete it from that table instead. It will delete both a restaurant and all comments on it, and you still have your integrity.
If you want to take advantage of foreign key constraint and normalize the attributes of comments (and ratings) across base tables, you may need to create relationship tables between base tables and comments (and ratings).
e.g. for Restaurants and Comments:
Restaurants
id (PK)
(attributes of restaurants...)
RestaurantComments
id (PK)
restaurantid (FK to Restaurants)
commentid (FK to Comments)
Comments
id (PK)
(attributes of comments...)