Comment system for 2 different entities - mysql

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.

Related

How Do I Organise This MySQL Database?

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

Relation Between Two Tables: make relationship between two tables

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

How do fields not selected for in a MySQL query affect query speed for the fields I am selecting on?

This is a theoretical question based on an application I have. I am wondering if there is some technical insight to be gained beyond just speed tests on my system.
I have the following two tables:
CREATE TABLE `files` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`url` varchar(255) NOT NULL DEFAULT '',
`processed` tinyint(1) unsigned NOT NULL DEFAULT '0',
`last_processed` timestamp NULL DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `url` (`url`),
) ENGINE=MyISAM AUTO_INCREMENT=1 DEFAULT CHARSET=latin1;
and...
CREATE TABLE `file_metas` (
`file_id` int(10) unsigned NOT NULL,
`title` varchar(255) NOT NULL DEFAULT '',
`description` varchar(1000) NOT NULL DEFAULT '',
`keywords` varchar(1000) NOT NULL DEFAULT '',
PRIMARY KEY (`file_id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
The file_metas data is long text strings about each file from the files table. Each file only has one entry in the file_metas table so these two tables could be combined.
I'm wondering what affect adding the long text fields to the files table will have on the performance of select statements done on the files table when I'm not selecting for title, description, or keywords. I'm curious about the technical details. Does simply having the text fields in the table slow queries not involving those fields? How does this work in general with MySQL MyISAM tables? Is there any good reason to keep the file_metas data in a separate table?

which is better code for maintaining the database and why?

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.

Querying two tables... in MySQL

CREATE TABLE IF NOT EXISTS `document`
(
`intId` int(11) NOT NULL auto_increment,
`chDocumentTitle` varchar(32) default NULL,
`dtLastUpdate` datetime default NULL,
`chUser` varchar(32) default NULL,
`chLink` varchar(256) default NULL,
`Keyword` varchar(256) default NULL,
`intParentid` int(11) NOT NULL,
PRIMARY KEY (`intId`),
KEY `dtLastUpdate` (`dtLastUpdate`,`chUser`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=10 ;
CREATE TABLE IF NOT EXISTS `category`
(
`intId` int(11) NOT NULL auto_increment,
`chName` varchar(32) NOT NULL,
`Isactive` tinyint(1) NOT NULL default '0',
`chnestUnder` int(5) NOT NULL default '0',
PRIMARY KEY (`intId`),
KEY `chName` (`chName`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=9 ;
Now I am looking for a query which will do the following...
Want to list out the documents of the categories... in hierarchical order.
Category One
Documents of Category One
Sub Category - [ If any ]
Documents of Sub Category
Based on this I need to generate XML.
This page has a very good explanation and plenty of helpful examples on how to work with hierarchical data in MySQL. In your situation it's definitely worth the read:
http://mikehillyer.com/articles/managing-hierarchical-data-in-mysql/
...
Also make sure to follow the link to
There's also a reference to this page, with tips on how to work with hierarchical data in your database with a bit of help from PHP.