I have a table "products" for my website. There is the product_id, image and bunch of information like manufacturer, health, age etc. When I started to work on my projekts I chose to save everything as ENUMs like this:
manufacturer ENUM('manufacturer1', 'manufacturer2', 'manufacturer3', 'manufacturer4'),
However dealing with more stuff I have realized that this is not the best approach for me. So I decided to create reference tables. For manufacturer it looks like this:
CREATE TABLE manufacturer(
manufacturer_id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
name VARCHAR(50) NOT NULL,
PRIMARY KEY (manufacturer_id ),
UNIQUE INDEX name (name)
);
but in products table I now have:
manufacturer_id INT(10),
The question is on what is the best way to assign value from reference table. I am using CI framework and it was very easy to display product in view. However now when I run query for product I get "3" instead of "manufacturer3".
I could use JOIN but I would have 7 JOINs. I created library with function that ataches the value. But I have to save all the possible values in that function or to query every reference table every time I use library.
I mean there are a lot of articles about why not to use ENUMs and I get that - I run in problems with ENUM in my project myself. I dont get how to convert those reference ids to real value (efectivelly, I dont think that 7 JOINs is a good way to that especially if I have to do that very often)
Related
I'm quite new to CakePHP and I'd like to think I've been getting the gist of it fairly quickly. My question is sort of more in relation to MySQL but I'll bring Cake back into it at the end.
I'm creating a forum/bulletin board sort of application. Currently I have a posts entry in my database that holds the usuals: id, title, body, etc, etc.
My problem: I want to implement various different types of 'posts'. Like Photo Posts, Text Posts, Staff Posts, etc (similar to how tumblr organizes its posts). Should I be making separate tables for each type of these posts, like text_posts, photo_posts, etc? OR can I have fields in the regular Post table like "image_url" that if its left empty upon creating, then I have the view interpret it as a text post?
And if I were to create separate tables for each of the different types, I would set all of those different posts in the bulletin board Controller so I can display them in the Bulletin View. But then in the view, how would I have them display in one nice feed based on when they were created? I don't want to have for loops that displays all text posts, all photo posts, etc. I want them to mesh them together.
It seems to me like you have a problem with inheritence in your database structure.
Relational databases don't support inheritance
Three possible ways I know off how to solve this problem are:
1.Single Table Inheritance (One table for all posts, will have a lot of NULL values then.)
2.Class Table Inheritance (Try to implement inheritance anyway but mapping each object you would create in PHP to a table.)
3.Concrete Table Inheritance (Seperate table for each type of post)
Which solutions is better for you I cannot tell. They each have their advantages and disadvantages.
Edit: The PHP part
Though I don't know much about PHP, you could probably do something like this:
If you choose option 3 to store the posts in your database you could still choose introduce the inheritance in PHP. Loop through the parent class objects (Post) and display properties specific to a child (Photo, Text etc.) by checking if it’s an instance of that object type.
In theory you could create a different table for each and write a view over it. Unfortunately MySQL does not support instead of trigger that you will need to insert.
Here is an example using sqlite3 that does it.
create table PhotoTable (
id integer not null PRIMARY KEY AUTOINCREMENT,
PhotoName varchar(255),
Camera varchar(255)
);
create table StaffTable (
id integer not null PRIMARY KEY AUTOINCREMENT,
StaffName varchar(255)
);
--- Odd way of seeding AUTOINCREMENT value in SQLite3
insert into StaffTable(StaffName) values('odd');
delete from StaffTable;
update SQLITE_SEQUENCE set seq = 100000 where name ='StaffTable';
create view posts as
select id, 'Photo' as Type, PhotoName, Camera, NULL as StaffName from PhotoTable
union all
select id, 'Staff' as Type, NULL as PhotoName, NULL as Camera,StaffName from StaffTable;
create trigger postsinsert
instead of insert on posts
for each row
begin
insert into PhotoTable(PhotoName, Camera) select new.PhotoName, new.Camera where New.Type ='Photo';
insert into StaffTable(StaffName) select new.StaffName where New.Type = 'Staff';
end;
insert into posts(Type, PhotoName, Camera) values('Photo','photo1','nk');
insert into posts(Type, PhotoName, Camera) values('Photo','photo2','canon');
insert into posts(Type, StaffName) values('Staff', 'spaceghost');
and you get the expected result of
select * from posts;
1|Photo|photo1|nk|
2|Photo|photo2|canon|
100001|Staff|||spaceghost
I think 2 tables should be better than creating new table for each type.
You can have posts table and post_types table, in posts table you can have post_type_id foreign key, this would help you grow types without having to create a new table each time.
Then in posts table, make the columns as generic as possible, so for example you can have a "value" column which you can be used to save image url or anything else based on the post type.
Also worth considering at this stage is if your post would need to have multiple types, in which case a bridge table would be handy, so one table for posts another for types and third to hold post and type id as foreign keys.
what is the way of designing an optimized schema's for a shopping website that can provide different filter options for different categories.
In TV Category the filters available are Type, Display Features, Display Size. Whereas in computer accessories like keyboard the filters available are Type and Interface. and the filters change for various products.
Filtering the result by cost and brand can be done easily as they have separate column in the table.
but how to design a table of items which have different types of multiple filters which varies by category. My guess would be having a column named filter for every item. that holds these data's. But is it the best way of using filters as the column filter have multiple filters.
Having one column surely is not the best way if you have a lot of data.
As I suppose, you can have some table tbl_product_filters with M:1 relation to your tbl_products that contains filter names and values for each product id.
Something like:
CREATE TABLE `tbl_product_filters`
(
`id` int(10) unsigned auto_increment PRIMARY KEY,
`product_id` ...,
`name` varchar(25) NOT NULL,
`value` varchar(255)
)..;
You can also normalize it further and isolate filter names as filter types in separate table to substitute string name to integer type_id. It would be faster I suppose.
I was just wondering if I might get some advice on the following:
I'm building a site in CodeIgniter in which exists a content type "portfolio_item".
The same portfolio item may be displayed in 3 places via checkbox controls:
Homepage, Member Page and Client Page.
I'm just wondering what the best way to implement this relationship in the database is. I could have 3 relationship tables for each of the above scenarios, but to me this seems overkill (the site is quite small).
I was thinking of using one relationship table with the following fields:
type (homepage, client or member)
show_on_id
portfolio_id
The intent of the type field is to determine which table to retrieve the "show_on_id" from (either clients or member), if the type is homepage then show_on_id is not required.
Is there any obvious disadvantage of doing it this way?
Yes, there is a bit of a disadvantage. You could end up with multiple rows for the same setting, each might contradict each other. So, how you insert rows into this table, is very important.
If you will not add any more sections, might as well have the portfolio table:
CREATE TABLE `portfolio`
(`id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
`content` TEXT NULL,
`showHome` BOOLEAN NULL,
`showClient` BOOLEAN NULL,
`showMember` BOOLEAN NULL)
And then the table which links the users to their portfolios,
CREATE TABLE `portfolio_user`
(`id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
`portfolio` INT NOT NULL,
`user` INT NOT NULL)
If you are going to add more places where the portfolio can be displayed later, or if these places are dynamic, your method will work. I would just change 'type' to 'place' as that is easier to understand, then either use ENUM or another table to define the places that the portfolio can be shown.
Can there be one or many portfolio items for each location?
If many, use link tables, if only one use direct foreign key field to link to the portfolio.
I would advice against using one link table for all three based on personal experience with exactly such designs and the problems that can surface later.
Hey I have two models User and City, where a user belongs to a city and a city has many users.
On the city table I have city_id and city_name.
I've used used cake bake and created the user model and when I add a new user the combos box under the city field is showing the id of the city instead of the name.
I've tried several methods to show the name of city instead of the id but I've failed.
You don't mention what you've tried, but usually you'd use the model's displayName property to set the field that should be used a record's "title". In your case, I'd think:
$this->displayName = 'city_name';
Note that in 1.3, it looks like the attribute name is displayField rather than displayName.
Cake requires a specific table layout for the automation to work. Rob explained how to get around it. But if you want to avoid writing the extra lines of code, you should consider organizing your tables accordingly.
CREATE TABLE `cities` (
`id` int(11) AUTO_INCREMENT NOT NULL,
`name` varchar(25) NOT NULL,
PRIMARY KEY (`id`)
)
When you bake this model, Cake will automatically use name as the display name. This will apply to every table you create. In addition, if you use id for the table, it will automatically know how to reference it as a foreign key from other tables as city_id.
I'm pretty new to OOP/OOD, and I realize I have a lot to learn, so I'd like to ask the SO community for their input.
Basically, I'm using CakePHP's MVC framework, and the online store I'm building is just using 2 models, Category and Product, described by the following CREATE statements:
CREATE TABLE `categories` (
`id` int(11) unsigned NOT NULL auto_increment,
`name` varchar(255) default NULL,
`parent_id` int(11) default NULL REFERENCES categories(`id`),
`lft` int(11) default NULL,
`rght` int(11) default NULL,
PRIMARY KEY (`id`)
);
CREATE TABLE `products` (
`id` int(11) unsigned NOT NULL auto_increment,
`name` varchar(255) default NULL,
`artist_id` int(11) default NULL REFERENCES artists(`id`),
`description` text default NULL,
`category_id` int(11) default NULL REFERENCES categories(`id`),
`status` enum('in stock', 'pre-order', 'out of stock') NOT NULL,
`price` decimal(6,2) default NULL,
`picture` varchar(255) default NULL,
`picture2` varchar(255) default NULL,
PRIMARY KEY (`id`)
);
The online store is going to encompass:
Music
CDs
DVDs
Apparel
Hoodies
T-shirts
Long-sleeve Tees
Babydolls
Hats
Misc Merch
Stickers
Posters
Tote Bags
Downloads
Ringtones
MP3s
Basically, that's the structure of the category tree, though we may add new categories in the future. Right now all products are treated equally as Product class objects, with their category_id being the only way to distinguish different types of products. The online store is also just one section of the site. The rest of the site contains information such as artist bios and discographies; thus I also have models/tables for: Artist, Album, Track.
Is this a good approach? Or should I be creating separate subclasses for CDs/T-shirts/MP3s/... which inherit from the Product class? I'd like to link each music CD in the store to the discography entry to automatically generate track listings and other information for the product description.
If this is not a good way to go about things, how would you do it instead? Also, what methods/properties should I include in my Category/Product class? And should I only list products in leaf nodes of the category tree?
Edit:
Obviously this design is incomplete. As Cyril pointed out, the Product.price field was missing, and there are still no provisions for sales. I'm actually still trying to work out how best to design & implement those aspects of the store. Most likely, I will just have another model called Orders, but actually processing orders is made more complicated by the fact that we are applying different shipping rates based on shipping destination and what the order contains.
I like more a configuration+behavior approach instead of the subclasses.
This can be bits of behaviors at the category level. Depending on the scenario, some behaviors could be associated to separate product types, like for something that applies to certain products regardless of the categories. For this last piece Smoking suggestion would also make a lot of sense, since you could have these extra behaviors associated to additional categories. This way as long as you are working with already coded behaviors, you can add new categories indicating which behaviors it will support.
A small variation, would be list of behaviors associated to the categories instead of the bits.
The additional classes would be for the behaviors, instead of having to mix it all under the product classes. If you need to associate an UI for these extra things, you can relate it to the behaviors, regardless of product types.
You could still keep the products table and make different "subcategories of products" if you use the polymorphic behavior. That's an easy way to keep all the common data in one place (price etc).
Alternatively, you could use the same polymorphic behavior on a table attributes and add anything product-specific as an attribute (name=>value pairs). It all depends on the idea in your head and the amount of data.
First solution is probably better if you plan to have a large database.
Yes, you probably should create separate subclasses for the different types of products, especially if they will have type specific functionality. Like the automatically generating of track listings you mention.
But even without that, by using separately named product classes you will make the code more readable and more logical when dealing with product type specific code.
You also might want to create a more specific database model.
Like
table: product
prod_id
...common stuff..
product_clothes
prod_id
...Clothes specific stuff...
product_music
prod_id
...music specific stuff...
product_merch
prod_id
...merchandise specific stuff..
Because music doesn't have a size measured in inches and clothes don't have a bitrate.
You should skip the category_id column and model the relationship more like a tag cloud. You will want to associate each product with one or more categories.
You should skip the artist_id column and model the relationship more like a tag cloud. You will eventually want to associate some product with multiple artists.
Categories are dated, you HAVE to use tag clouds. As a rule you should NEVER create tables with a references statement; UNLESS every column in the table has a references statement.
No,
You should definitely not create separate subclasses unless you need some mumbo-jumbo magic (like custom t-shirt logos, etc) which cannot be achieved a simple category division). Even in that case you may be safe putting in an extra flag field in the category class (HasLogo for example).
But the design does not impress me yet. What kind of store has no provision for sales? What about price field?
You could also put the Picture in a separate table for the sake of flexibility.
What are you using lft/rght for? You can use a simple Inde property to store the category's place in the tree, but remember you will need to update each time you delete/add a category.