Multiple Tables...
CREATE TABLE IF NOT EXISTS `pictures` (
`id` bigint(20) NOT NULL auto_increment,
`title` varchar(255) NOT NULL,
`url` varchar(255) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE IF NOT EXISTS `propPictures` (
`id` bigint(20) NOT NULL auto_increment,
`picture_id` varchar(255) NOT NULL,
`property_id` varchar(255) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
OR
CREATE TABLE IF NOT EXISTS `pictures` (
`id` bigint(20) NOT NULL auto_increment,
`title` varchar(255) NOT NULL,
`url` varchar(255) NOT NULL,
`property_id` varchar(255) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
????
thank you
It depends. Will every picture have exactly one property_id? If so then a single table is fine.
A Property can and probably will have multiple pictures, so what you want is a property table and then a picture table that includes property id and has a foreign key to the porperty table.
Incidentally ID is a terrible choice for the id field. It creates problems with reporting and can cause accidental join problems. Two tables should almost never use the same name for fields which mean something different. Use tablenameID instead.
It looks like you're suggesting table1 for pictures, and table2 for any properties it may have. This would usually be better than a single table design as it makes it easy to handle any given picture having, 0, 1, or many more properties.
With a one-to-one relationship between pictures.id and property_id, a single table would suffice. If this relationship changes to one to many, a second table will become necessary to relate the one pictures.id to the many property ids.
Related
I am currently working with a database that was auto generated by a tool (and is used in production)
(I will only speak about what is interesting for the question)
I have three tables : user, movie and userMovie.
the command show create table user return something like :
CREATE TABLE `users` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(255) DEFAULT NULL,
`email` varchar(255) DEFAULT NULL,
`password` varchar(255) DEFAULT NULL,
`other_field_1` varchar(255) DEFAULT NULL, -- not actual field name
PRIMARY KEY (`id`),
FULLTEXT KEY `SEARCH_USERS` (`username`,`other_field_1`)
)
the command show create table movie return something like :
CREATE TABLE `movie` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) DEFAULT NULL,
`link` varchar(255) DEFAULT NULL,
`another_field_1` varchar(255) DEFAULT NULL, -- not actual field name
`another_field_2` varchar(255) DEFAULT NULL, -- not actual field name
PRIMARY KEY (`id`),
FULLTEXT KEY `SEARCH_MOVIES` (`name`,`link`,`another_field_1`,`another_field_2`)
)
the command show create table userMovie return something like :
CREATE TABLE `userMovie` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`Name` varchar(255) DEFAULT NULL,
`user` int(11) DEFAULT NULL,
`field1` varchar(255) DEFAULT NULL, -- not actual field name
`field2` varchar(255) DEFAULT NULL, -- not actual field name
`field3` varchar(255) DEFAULT NULL, -- not actual field name
PRIMARY KEY (`id`),
FULLTEXT KEY `SEARCH_USER_MOVIE` (`Name`,`field1`,`field2`,`field3`)
)
Obviously, there is several issue with this code, the main ones being :
There is no foreign key,
The field userMovie.Name contain the name of the movie, not the id
I'm well aware of the inconsistency risk, but I'm more ignorant about the potential performance issue. Especially, there is a lot of records in the userMovie table, and we have to join it quite often with the movie table (and the user table)
However, as userMovie.Name is in the "FULLTEXT KEY", does that mean it is indexed ?
By the way, I think that only the tool previously mentioned had an use of this, and can probably be removed if needed.
I would want to know if there is a performance issue and ways to improve it. (It would also be awesome if the modification I'll be doing are "safe", as I don't want to break anything)
The column(s) in a FULLTEXT index are usable only for MATCH...AGAINST.
If you also want a BTree index on the column(s), provide a separate INDEX.
You can do
WHERE MATCH(`Name`,`field1`,`field2`,`field3`) AGAINST("...")
AND field4 > 123
Or even
WHERE MATCH(`Name`,`field1`,`field2`,`field3`) AGAINST("...")
AND name = 'abc'
However, this second format makes little sense. Usually a column is searched by either FULLTEXT or a regular index, not both.
What is the intent of the table userMovie? The name sounds like a many-to-many mapping table (eg, which movies each user has watched), but the columns do not reflect that.
To address a "performance issue", we need to see the SELECTs -- they have performance issues, not the schema. They guide what indexes are useful.
I am making my first project that uses MySQL. To do so, I need to organise the following values- Email, Subject, Questions, Answers
Here's an image showing what I had in mind
Basically, each user, identified by an email address, makes questions and answers pertaining to a given list of subjects. I am not sure how to organise it in a way that would be normalised.
Being new to MySQL, I thought it would be better to ask more experienced people first. Any ideas on how to organise this, and any tips for organising MySQL databases in general?
That image looks good to me, however...
If I read your project constraints correctly, you are limited to a discrete set of available subjects? If that is the case, a separate table of the available subjects would probably be good.
So it could be as simple as one table, but personally I might consider two (the second for subjects) just to avoid folks submitting multiple / small variations of the same subject (e.g. Math and Mathematics).
If you want to get fancy, maybe think about the implications of similar variations of essentially the same question being posted. Hypothetically, if the database were for an FAQ application, when someone is drafting a question that is very similar to another question that has already received a reply, you may want to redirect that person to that question before they submit their new question.
This is the simplest way in MySQL I can think of.
DROP TABLE IF EXISTS `_user`;
CREATE TABLE `_user` (
`user_id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(32) DEFAULT NULL,
`password` varchar(40) DEFAULT NULL,
`first_name` varchar(32) DEFAULT NULL,
`last_name` varchar(32) DEFAULT NULL,
`email_address` varchar(50) DEFAULT NULL,
PRIMARY KEY (`user_id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
DROP TABLE IF EXISTS `questions`;
CREATE TABLE IF NOT EXISTS `questions` (
`question_id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) DEFAULT NULL,
`subject_id` int(11) DEFAULT NULL,
`question` varchar(200) DEFAULT NULL,
PRIMARY KEY (`question_id`),
KEY `user_id` (`user_id`),
KEY `subject_id` (`subject_id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 ;
DROP TABLE IF EXISTS `answers`;
CREATE TABLE IF NOT EXISTS `answers`(
`answer_id` int(11) NOT NULL AUTO_INCREMENT,
`question_id` int(11) DEFAULT NULL,
`user_id` int(11) DEFAULT NULL,
`answer` varchar(200) DEFAULT NULL,
PRIMARY KEY (`answer_id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 ;
DROP TABLE IF EXISTS `subjects`;
CREATE TABLE IF NOT EXISTS `subject` (
`subject_id` int(11) NOT NULL AUTO_INCREMENT,
`subject` varchar(200) DEFAULT NULL,
PRIMARY KEY (`subject_id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 ;
The query should look something like this--
$query = "SELECT
questions.question,
answers.answer,
subjects.subject,
_user.email_address
FROM questions
INNER JOIN answers
ON answers.question_id = questions.question_id
LEFT JOIN subjects
ON subjects.subject_id = questions.subject_id
LEFT JOIN _user
ON _user.user_id = questions.user_id
";
This is the preferred design for you case:
Each user can has many questions on every subject,
And each Subject can has many users' questions
In each table you can add the remaining data you want
I am trying to create a comment system.
The database design for the things, I would like to comment on (posts and articles):
TABLE `posts` (
`post_id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`post_text` text NOT NULL,
`user_id` int(11) unsigned NOT NULL,
PRIMARY KEY (`post_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
TABLE `articles` (
`article_id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`article_text` text NOT NULL,
`user_id` int(11) unsigned NOT NULL,
PRIMARY KEY (`article_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
The problem
Each comment should be linked to either a post or an article.
My attempts
Option No.1
I put the possibility for an article_id as well as a post_id into the same table and they both can be left empty.
TABLE `comments` (
`comment_id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`comment_text` text NOT NULL,
`user_id` int(11) unsigned NOT NULL,
`post_id` int(11) NULL,
`article_id` int(11) NULL,
PRIMARY KEY (`article_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
Like this there would be an article_id, when an article is commented and a post_id if a post is commented.
But is it a good idea to leave both fields NULL, if one should always be NOT NULL?
Option No.2
Creating two seperate tables. One for post comments and one for article comments.
TABLE `article_comments` (
`comment_id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`comment_text` text NOT NULL,
`user_id` int(11) unsigned NOT NULL,
`article_id` int(11) NOT NULL,
PRIMARY KEY (`article_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
TABLE `post_comments` (
`comment_id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`comment_text` text NOT NULL,
`user_id` int(11) unsigned NOT NULL,
`post_id` int(11) NOT NULL,
PRIMARY KEY (`article_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
Like this nobody, who should be NOT NULL is NULL.
However, I do not know if this might become a perfomance issue and I am pretty sure this would lead to a lot of repetition in my PHP stuff.
Is there a better way to do this?
I have no experience in such things and would be very thankful for help!
There are a few considerations here.
Object vs. Relational mappings
PHP offers OO-style programming which would allow you to create an abstract super-class of article and post, to which comments could then generically be linked. OO structures like this do not map well to relational databases though unfortunately and so you have to make compromises.
Use cases for accessing the data
How and where do you need to access the comment data. This can drive the way you structure and potentially de-normalise your data and create indexes also.
Where to enforce data integrity constraints
It is nice to be able to have the database enforce clean data when you can, but this isn't always possible in reality (or you have to jump through hoops like in your second option above) to achieve it. Personally, this is one of those cases where I wouldn't bother trying to get the database to manage it for me, but rather ensure this is managed (and error handled) appropriately within your application.
Ultimately, I have not come across one correct answer to this problem. Of the two options you suggest above, Option 1 would be my own preference. However, an alternative you should consider is to merge your Posts and Articles tables into one 'Content' table with a content_type property or similar (which allows you to model them with an abstract superclass and concrete sub-classes in PHP). Then your comments table just references that generically.
Using MySQL workbench, I copied the create statement from a few related tables to put into a clean schema. They all reference each other in some way so there is no inherent order I can create them in. How can I just force MySQL to create the tables while ignoring any warning that may occur, just until the rest of the tables are created?
Would I have to group it inside a transaction of some sort?
A very simple example would be:
CREATE TABLE `vehicle` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`gallery_id` int(11) DEFAULT NULL,
`make_id` int(11) NOT NULL,
`model_id` int(11) DEFAULT NULL,
`make` varchar(100) DEFAULT '',
`model` varchar(100) DEFAULT '',
`colour_id` int(11) DEFAULT NULL,
`currency_id` int(11) NOT NULL DEFAULT '1',
`fuel_id` int(11) DEFAULT NULL,
`status_id` int(11) DEFAULT NULL,
`stock_code` varchar(100) DEFAULT NULL,
`registration` varchar(20) DEFAULT NULL,
`title` varchar(100) DEFAULT NULL,
`description` text,
`month` tinyint(4) DEFAULT NULL,
`public` tinyint(4) NOT NULL DEFAULT '0',
`sold` tinyint(4) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
KEY `vehicle_fk_idx` (`status_id`),
CONSTRAINT `vehicle_fk` FOREIGN KEY (`status_id`) REFERENCES `vehicle_status` (`id`) ON DELETE SET NULL ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
CREATE TABLE `vehicle_status` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`slug` varchar(100) DEFAULT NULL,
`title` varchar(100) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `slug_UNIQUE` (`slug`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=latin1;
vehicle references vehicle_status which would mean that vehicle_status would have to be created first. How would I create vehicle first and then vehicle_status without adding the reference afterwards?
You do not define foreign keys when creating tables, you would have them in a separate query like this:
ALTER TABLE `vehicle`
ADD CONSTRAINT `vehicle_ibfk_1` FOREIGN KEY (`status_id`)
REFERENCES `vehicle_status` (`id`) ON DELETE SET NULL ON UPDATE CASCADE;
So you would first create tables and then create foreign keys.
The way I personally do is I have all CREATE TABLE queries in one file that I know I can simply just import without any errors. I have all CONSTRAINT queries in a separate file that I import after all the tables have been created and I have all INSERT INTO queries in a separate file that adds data after all constraints and tables have been set.
It looks like vehicle_status is a lookup table, while vehicle is a primary transaction table.
In general, lookup tables do not reference other tables, although there can be designs where one lookup table references another lookup table. In your case, it's simple: just create vehicle_status first. If your schema has a hundred tables in it, it's going to involve a little work to order the create commands in the right sequence.
There are designs where the reference chain forms a circle. In such a case, you'll have to do what GGio suggests: add the constraints later. There are other problems with designs involving circular references, and those problems may or may not be present in your schema.
When you go to populate the tables, you'll have to worry about order as well. In general, you'll have to populate the lookup tables first, before you begin to populate the transaction tables. Otherwise you'll get reference violations at load time.
I have two tables as post and gallery, and i have made a relationship gallery to post table.
My requirement is,
When user upload content it store in the post table(content field) ,
If user upload the images are video i want to store the images/video name in, gallery table and the gallery id refers to the post table. I dont know how to do it. please any one help me?
post table:
CREATE TABLE IF NOT EXISTS `post` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`user_id` bigint(20) unsigned NOT NULL,
`gallery_id` bigint(20) unsigned NOT NULL,
`content` longtext,
`photo` varchar(128) DEFAULT NULL,
`video` varchar(128) DEFAULT NULL,
`created` timestamp NULL DEFAULT NULL,
`updated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `fk_forum_post_user` (`user_id`),
KEY `fk_forum_post_gallery` (`gallery_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=10 ;
ALTER TABLE `post`
ADD CONSTRAINT `fk_post_gallery` FOREIGN KEY (`gallery_id`) REFERENCES `gallery` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
gallery table
CREATE TABLE IF NOT EXISTS `gallery` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`user_id` bigint(20) unsigned NOT NULL,
`type` int(11) NOT NULL DEFAULT '1' COMMENT '1- Photo, 2-Video, 3-Documents, 4-Unknown',
`profile_picture` varchar(50) DEFAULT NULL,
`forum_image` varchar(200) DEFAULT NULL,
`forum_video` varchar(200) DEFAULT NULL,
`forum_video_link` varchar(200) DEFAULT NULL,
`created` timestamp NULL DEFAULT NULL,
`updated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `fk_gallery_user` (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=60 ;
is any other idea is to do or how can i move forward?
There are a lot of ways you can perform this tasks. you can perform logic on code level as well as on database level. however here is a quick answer . hope this could help you
First Remove the column (gallery_id) as it is possible that user may have more than one images or video for single post or user may not want to upload any image / video in this case your gallery id would be null.
In this case your Pk would be only postId
your gallery table is fine
Make a third table name PostGalleryRealation
make 2 column in this table PostId as fk from post table and galleryid as fk from gallery table.
this is basically for one to many relation as one post may have more than one gallery
insert the post id and gallery id in PostGalleryRealation table
Finally you can write this query to fetch the result for you.
I did not test the query, so it's just a basic idea
Select p.id, p.content, p.created, g.type, g.profilepicture, g.forum_image
from post p, gallery g, postgalleryrelation pgr
where p.id = pgr.postid
and g.id = pgr.galleryid
and p.id = 1
It's just an idea. You can do much better.
YII have relation option while creating CRUD using gii. For that, you have to create tables with foreign key relationship. So YII will automatically create the relation in coding level. You have to choose the option Build Relation while creating model for both tables.
Check the Yii relation tutorials for more information