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.
Related
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)
I'm implementing a flashcard app, hence my FLASHCARDS table contains fields such as QUESTION and RESPONSE, and my USERS table is just that - names and personal info of my flashcard app.
Here's where I get confused. The FLASHCARDS table will hold 100s of questions and responses categorized into "groups" of flashcards (or decks). When the USERS "use" the flashcards they will also be able to decide if the question was EASY, NORMAL, or DIFFICULT - hence modifying the time till the card is next shown.
If I only had one user this wouldn't be a problem - I'd just modify the FLASHCARDS table accordingly, but I´ll also have 100s of users. How can I modify FLASHCARDS table depending on each USERS decision of EASY, NORMAL or DIFFICULT and keep record of all of this for each user (I imagine in USERS table).
You've got a many-to-many relationship between the "Flashcard" entity and the "User" entity.
A particular "User" makes a decision about a particular "Flashcard".
A "User" can make a decision on zero, one or more "Flashcard".
A "Flashcard" can be decided by zero, one or more "User".
That's a classic many-to-many relationship.
In the relational model, we introduce a new relationship table, that establishes the relationship between "User" and "Flashcard"
As an example of what this table might look like:
CREATE TABLE user_flashcard
( user_id INT UNSIGNED NOT NULL COMMENT 'fk ref user'
, flashcard_id INT UNSIGNED NOT NULL COMMENT 'fk ref flashcard'
, decision VARCHAR(30) COMMENT 'EASY,NORMAL,DIFFICULT'
, PRIMARY KEY (user_id,flashcard)
, CONSTRAINT FK_user_flashcard_user
FOREIGN KEY (user_id) REFERENCES user(id)
, CONSTRAINT FK_user_flashcard_flashcard
FOREIGN KEY (flashcard_id) REFERENCES flashcard(id)
)
You could add additional attributes, for example: the last time the user viewed the flashcard, the number of times the user has viewed it.
You also need to consider whether this is just a pure relationship, or if this is might actually be an entity in your model.If we have repeating attributes, or any other entities might be related to this table, we'd likely want to introduce a simple primary key (id) that other tables can reference in a foreign key.
We also want to think about this, do we want a user to have more than one decision on a flashcard? Does (user_id,flashcard_id) need to be unique, or should it be non-unique.
The key to database design is data analysis. And one of the best tried-and-true techniques for "doing" data analysis is Entity Relationship Modeling.
FOLLOWUP EXAMPLE DEMONSTRATION
As a demonstration of how this "relationship" table works, I've created a very short SQL Fiddle, demonstrating the kind of questions that can be fairly easily answered using some fairly simple SQL.
SQL Fiddle Here http://sqlfiddle.com/#!9/090ee/5
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.
So I'm a visual designer type guy who has learned a respectable amount of PHP and a little SQL.
I am putting together a personal multimedia portfolio site. I'm using CI and loving it. The problem is I don't know squat about DB design and I keep rewriting (and breaking) my tables. Here is what I need.
I have a table to store the projects:
I want to do fulltext searcheson titles and descriptions so I think this needs to be MyISAM
PROJECTS
id
name (admin-only human readable)
title (headline for visitors to read)
description
date (the date the project was finished)
posted (timestamp when the project was posted)
Then I need tags:
I think I've figured this out. from researching.
TAGS
tag_id
tag_name
PROJECT_TAGS
project_id (foreign key PROJECTS TABLE)
tag_id (foreign key TAGS TABLE)
Here is the problem I have FOUR media types; Photo Albums, Flash Apps, Print Pieces, and Website Designs. no project can be of two types because (with one exception) they all require different logic to be displayed in the view. I am not sure whether to put the media type in the project table and join directly to the types table or use an intermediate table to define the relationships like the tags. I also thinking about parent-types/sub-types i.e.; Blogs, Projects - Flash, Projects - Web. I would really appreciate some direction.
Also maybe some help on how to efficiently query for the projects with the given solution.
The first think to address is your database engine, MyISAM. The database engine is how MySQL stores the data. For more information regarding MyISAM you can view: http://dev.mysql.com/doc/refman/5.0/en/myisam-storage-engine.html. If you want to have referential integrity (which is recommended), you want your database engine to be InnoDB (http://dev.mysql.com/doc/refman/5.0/en/innodb-storage-engine.html). InnoDB allows you to create foreign keys and enforce that foreign key relationship (I found out the hard way the MyISAM does not). MyISAM is the default engine for MySQL databases. If you are using phpMyAdmin (which is a highly recommended tool for MySQL and PHP development), you can easily change the engine type of the database (See: http://www.electrictoolbox.com/mysql-change-table-storage-engine/).
With that said, searches or queries can be done in both MyISAM and InnoDB database engines. You can also index the columns to make search queries (SELECT statements) faster, but the trade off will be that INSERT statements will take longer. If you database is not huge (i.e. millions of records), you shouldn't see a noticeable difference though.
In terms of your design, there are several things to address. The first thing to understand is an entity relationship diagram or an ERD. This is a diagram of your tables and their corresponding relationships.
There are several types of relationships that can exist: a one-to-one relationship, a one-to-many relationship, a many-to-many relationship, and a hierarchical or recursive relationship . A many-to-many relationship is the most complicated and cannot be produced directly within the database and must be resolved with an intermittent table (I will explain further with an example).
A one-to-one relationship is straightforward. An example of this is if you have an employee table with a list of all employees and a salary table with a list of all salaries. One employee can only have one salary and one salary can only belong to one employee.
With that being said, another element to add to the mix is cardinality. Cardinality refers to whether or not the relationship may exist or must exist. In the previous example of an employee, there has to be a relationship between the salary and the employee (or else the employee may not be paid). This the relationship is read as, an employee must have one and only one salary and a salary may or may not have one and only one employee (as a salary can exist without belonging to an employee).
The phrases "one and only one" refers to it being a one-to-one relationship. The phrases "must" and "may or may not" referring to a relationship requiring to exist or not being required. This translates into the design as my foreign key of salary id in the employee table cannot be null and in the salary table there is no foreign key referencing the employee.
EMPLOYEE
id PRIMARY KEY
name VARCHAR(100)
salary_id NOT NULL UNIQUE
SALARY
id PRIMARY KEY
amount INTEGER NOT NULL
The one-to-many relationship is defined as the potential of having more than one. For example, relating to your portfolio, a client may have one or more projects. Thus the foreign key field in the projects table client_id cannot be unique as it may be repeated.
The many-to-many relationship is defined where more than one can both ways. For example, as you have correctly shown, projects may have one or more tags and tags may assigned to one or more projects. Thus, you need the PROJECT_TAGS table to resolve that many-to-many.
In regards to addressing your question directly, you will want to create a separate media type table and if any potential exists whatsoever where a project is can be associated to multiple types, you would want to have an intermittent table and could add a field to the project_media_type table called primary_type which would allow you to distinguish the project type as primarily that media type although it could fall under other categories if you were to filter by category.
This brings me to recursive relationships. Because you have the potential to have a recursive relationship or media_types you will want to add a field called parent_id. You would add a foreign key index to parent_id referencing the id of the media_type table. It must allow nulls as all of your top level parent media_types will have a null value for parent_id. Thus to select all parent media_types you could use:
SELECT * FROM media_type WHERE parent_id IS NULL
Then, to get the children you loop through each of the parents and could use the following query:
SELECT * FROM media_type WHERE parent_id = {$media_type_row->id}
This would need to be in a recursive function so you loop until there are no more children. An example of this using PHP related to hierarchical categories can be viewed at recursive function category database.
I hope this helps and know it's a lot but essentially, I tried to highlight a whole semester of database design and modeling. If you need any more information, I can attach an example ERD as well.
Another posibble idea is to add columns to projects table that would satisfy all media types needs and then while editting data you will use only certain columns needed for given media type.
That would be more database efficient (less joins).
If your media types are not very different in columns you need I would choose that aproach.
If they differ a lot, I would choose #cosmicsafari recommendation.
Why don't you take whats common to all and put that in a table & have the specific stuff in tables themelves, that way you can search through all the titles & descriptions in one.
Basic Table
- ID int
- Name varchar()
- Title varchar()
etc
Blogs
-ID int (just an auto_increment key)
-basicID int (this matches the id of the item in the basic table)
etc
Have one for each media type. That way you can do a search on all the descriptions & titles at the one time and load the appropriate data when the person clicked through the link from a search page. (I assume thats the sort of functionality you mean when you say you want to be able to let people search.)
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.