I am trying to build a system where the user can add a question and the other users can be commenting on his question or voting.
The main functions are :
1. user can add a question.
2. user can comment on his or other users questions.
3. user can replay (comment) on his or other users comments.
4. user can vote on other users questions.
The data schema that I build is as following (Examples):
Question: {
id: "question_Q1",
title: "How to learn python in one week?",
body: "I am trying to learn a new language .............",
images: {"python1.png","python2.png","python3.png","python5.png"},
tags: {"python","programing"},
user_id: "user_123456",
voters: [
{id:"user_123457", username:"John F.M"},
{id:"user_123458", username:"Sarah K.P"}
],
create_timeDate: "02/01/2018 11:00 pm",
update_timeDate: "21/02/2018 10:12 am"
comments: [
{ id: "comment_c1",
body:"you can learn it from ....",
images: null,
create_timeDate: "12/04/2018 11:00 pm",
update_timeDate: "15/04/2018 10:12 am",
replay: null},
{ id: "comment_c2",
body:"watch youtube for more information .....",
images: {"youtube.gif"},
create_timeDate: "19/04/2018 09:43 pm",
update_timeDate: "25/04/2018 11:10 pm",
replay: [
{ id: "replay_comment_c1",
body:"ohh thanks",
images: null,
create_timeDate: "14/04/2018 01:00 am",
update_timeDate: "20/04/2018 03:12 am",
replay: null
},
]
}
]
}
Is it correct what I am doing?
And what about voting? I don't know how to implement in it in my DB schema. I want to do the same voting system in the stack overflow but only on questions (without on comments).
I would create these tables: Questions, Images, QuestionTags, QuestionVoters, QuestionTag and Comments.
Table Question:
QuestionID,
title,
body,
user_id,
Table Questionvoters:
VoteID,
QuestionID (foreign Key to the Question table),
UserID
Table QuestionTagMapping:
QuestionID (foreign key to the Question table)
TagID (foreign key to the Tags table)
Table QuestionTag:
TagID
Tag
Table Comments:
Commentid,
QuestionID (foreign key to the Question table),
CommentReplyID: (if a comment replies to another comment put the id of this comment there),
body,
create_timeDate,
update_timeDate
Table Images:
ID (ID of the Comment or the Question),
Image
Update
Here is an example how i would solve your problem. I used a SQL Server database. The explanations are in the code written in comments.
--store the user information here, you don't need to store any pw if you want
--... we only need the iduser for our example
CREATE TABLE sUser
(
iduser varchar(100) PRIMARY KEY,
username varchar(100) not null,
--that could be other columns...
/*
--I have not stored any Password Hashes in DB, i am actually not sure if 1000 is the right length
pwhash varchar(1000),
email varchar(256),
*/
)
--store the Question and Comment data in this table
--I don't store Images or Tags in this table because I do no want to have multiple rows per post.
--If you had multiple rows for one post, it would cause problems when you update the data
CREATE TABLE Post
(
--I would not make the post id a varchar but in your example you defined a key for example like this 'question_Q1'
IDPost varchar(100) Primary Key,
--is only filled if the post is a question
title varchar(100) null,
body text not null,
iduser varchar(100) not null,
--create the link to which question or comment a comment belongs
ReplyID varchar(100) null,
create_timeDate datetime2 not null,
update_timeDate datetime2 not null,
--creates an reference to the table itself, to a "mother" question or comment
FOREIGN KEY (ReplyID) REFERENCES Post(IDPost),
--creates a reference to the table users, so you can only insert a question or comment if the specified user exists
FOREIGN KEY (iduser) REFERENCES sUser(iduser),
)
--stores votes
CREATE TABLE QuestionVoter
(
--with this column you can map the vote to the Question
IDPost varchar(100) not null,
--0 if the vote is negative, 1 if the vote is positive
Vote bit not null,
iduser varchar(100) not null,
PRIMARY KEY(IDPost,iduser),
--creates a reference to the table Post, so you can only insert a vote in this table if the PostID --> the Question exists in the Post table
FOREIGN KEY (IDPost) REFERENCES Post(IDPost)
)
--here you can specify a set of Tags
CREATE TABLE QuestionTag
(
IDTAG int Primary Key,
Tag varchar(100) not null
)
--create a mapping from a Question to the votes, the benefit for creating a mapping Table from the table Posts to the table QuestionTag,
--is that you can specify a set of gags and you don't have to store gags multipile times.
CREATE TABLE QuestionTagMapping
(
--with this column IDPost you map the QuestionTag to the question
IDPost varchar(100) not null,
IDTAG int not null,
PRIMARY KEY(IDPost, IDTAG),
FOREIGN KEY (IDPost) REFERENCES Post(IDPost),
FOREIGN KEY (IDTAG) REFERENCES QuestionTag(IDTAG)
)
--store your ImagePath in this table
CREATE TABLE Images
(
--this column is again for the mapping to the post
IDPost varchar(100) NOT NULL,
ImagePath varchar(256) not null,
PRIMARY KEY(IDPOST, ImagePath),
FOREIGN KEY (IDPost) REFERENCES Post(IDPost)
)
--example insert
--in your case i would not write plain sql, use a ORM Framework like JPA, Entity FrameWork Core to persist the data, but for this example its more then enough
--insert the Users
insert into sUser
values('user_123456','USER'),('user_123457','John F.M'),('user_123458','Sarah K.P')
--insert the Question
insert into Post
values('question_Q1', 'How to learn python in one week?', 'I am trying to learn a new language .............', 'user_123456',null,getdate(),getdate())
--insert the images for the Question
insert into Images
values('question_Q1','python1.png'),('question_Q1','python2.png')
--insert the votes for the question
insert into QuestionVoter
values('question_Q1', 1,'user_123457'),('question_Q1',1,'user_123458') --etc.
--specify QuestionTags
insert into QuestionTag
values(1, 'python'),(2, 'programming')
--select * from QuestionTag
--assagin the tags to a question via the QuestionTagMapping Table
insert into QuestionTagMapping
values('question_Q1',1),('question_Q1',2)
--insert comments
insert into Post
values('comment_c1',/*title is null becouse comments dont have titles*/ null, 'you can learn it from ....','user_123457'
,/*insert the ReplyID to make a reference to question where the comment was postet*/ 'question_Q1',/*GETDATE() is just for example that the field have values*/GETDATE(), GETDATE())
,('comment_c2',null, 'watch youtube for more information .....','user_123457', 'question_Q1',GETDATE(), GETDATE())
,('replay_comment_c1',null, 'ohh thanks','user_123456', 'comment_c2',GETDATE(), GETDATE())
--Example queries
--Get the amount of votes
SELECT p.IDPost, count(*) as AmountVotes, sum(cast(v.Vote as int)) as PositivVotes, sum(IIF(v.Vote = 0,1,0)) as NegativVotes
FROM Post p
LEFT JOIN QuestionVoter v on p.IDPost = v.IDPost
WHERE p.IDPost = 'question_Q1'
GROUP BY p.IDPost
--GET the comments for a question
SELECT *
FROM Post q
--JOIN via the ReplayID the comments with questions or subcomments
LEFT JOIN Post c on q.IDPost = c.ReplyID
--get the sub comments with another join on ReplayID of the subcomment and the IDPost of the comments
LEFT JOIN Post sc on c.IDPost = sc.ReplyID
WHERE q.IDPost = 'question_Q1'
Related
I'm very beginner at MySQL and have just started to play around with foreign keys and INNER JOIN operator.
So I've made a few tables like:
CREATE TABLE `models`
(
`id` TINYINT UNSIGNED NOT NULL AUTO_INCREMENT,
`name` VARCHAR (255) NOT NULL,
`price` MEDIUMINT UNSIGNED NOT NULL,
PRIMARY KEY( `id` )
);
CREATE TABLE `vendors`
(
`id` TINYINT UNSIGNED NOT NULL AUTO_INCREMENT,
`name` VARCHAR (255) NOT NULL,
`id_model` TINYINT UNSIGNED NOT NULL,
PRIMARY KEY( `id` ),
FOREIGN KEY (`id_model`) REFERENCES models(`id`)
);
CREATE TABLE `cars`
(
`serial_number` MEDIUMINT UNSIGNED NOT NULL,
`id_vendor` TINYINT UNSIGNED NOT NULL,
FOREIGN KEY (`id_vendor`) REFERENCES vendors(`id`),
PRIMARY KEY( `serial_number` )
);
I know how to get output with that. However, the problem is that I don't know how to insert data properly. All I can do is insert data table by table. But how to do it in one query, and if I am inserting Honda Civic and already have Honda Accord, for example, wouldn't it duplicate Honda vendor in the database?
It seems that the structure of the database is not really coherent. Maybe I don't understand what you are trying to do, but ... anyway, here goes.
Assuming that what you want to do is store a list a of cars in a properly normalized relational database, first thing you want to do is think what is happenning in "real life":
Manufacturers (vendors) make/sell cars
Manufacturers (vendors) make different models of cars
Cars have a model (and a serial number in your case)
Models belong to a vendor (manufacturers)
Considering this, your table structure is:
Vendors
- id
- name
Models
- id
- name
- vendor ( foreign key => vendor.id )
Cars
- id
- serial_number
- model ( foreign key => model.id )
You don't need to have a reference to the vendor in the cars table becoause you have a reference to the model, which in turn has a reference to the vendor.
Whe inserting, you do it one by one, making sure that the foreign key entries already exist.
When you insert a car object, you just need to provide the model id.
When you insert a model object you need to provide a vendor id.
So the Honda Civic/Accord situation does not duplicate Honda. The Tables should be something like this:
Vendor
id, name
1, "Honda"
Model
id, name, vendor
1, "Civic", 1
2, "Accord", 1
Cars
id, serial_no, model
1, "A serial", 2 -> a honda accord
2, "Another serial", 1 -> a honda civic
Hope this helps somewhat.
You do need to check if duplicated record exists yourself.
IF EXISTS (SELECT * FROM vendors WHERE Name = 'Honda')
BEGIN
-- Insert into cars with existing vendor id
END
ELSE
BEGIN
IF EXISTIS (SELECT * FROM models WHERE Name = 'your model name')
BEGIN
-- insert into vendors with existing model id
END
ELSE
BEGIN
-- insert into models
-- insert into vendors
-- insert into cars
END
END
You can create stored procedure for it and pass car, vendor and model as parameters.
Or you can list models first, insert them; then all vendors and all cars. Just a silly answer. Welcome more sophisticated solutions.
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
I am creating a job seek website with PHP and MySQL, one question is how to design the database better? The basic function of the website is that 'jobseekers' can login and search jobs, upload CVs, and 'employers' can login and post jobs, and browser CVs. Currently I just created 2 tables:
-- Table structure for table users
to analyze the table sturctures for a job seek website(using MySQL and PHP) [on hold]
-- user_type: 0 - jobseekers
-- 1 - employers
-- 2 - administrator
CREATE TABLE users (
user_id INT UNSIGNED NOT NULL AUTO_INCREMENT,
first_name VARCHAR(20) NOT NULL,
last_name VARCHAR(40) NOT NULL,
email VARCHAR(80) NOT NULL,
pass CHAR(40) NOT NULL,
user_type TINYINT(1) UNSIGNED NOT NULL DEFAULT 0,
active CHAR(32),
last_login DATETIME NOT NULL,
registration_date DATETIME NOT NULL,
PRIMARY KEY (user_id),
UNIQUE KEY (email),
INDEX login (email, pass)
) ENGINE = INNODB;
-- Table structure for table jobs
CREATE TABLE jobs (
job_id INT(11) NOT NULL AUTO_INCREMENT,
title VARCHAR(200) NOT NULL,
description text NOT NULL,
county VARCHAR(30) NOT NULL,
PRIMARY KEY (job_id)
) ENGINE = MYISAM ;
But I feel just two tables might not be enough, and the user table maybe need to be broke down. Any suggestion how to improve the design?
Perhaps you may want 4 tables;
2 to store the user details
jobseeker_details_table; ( name, address, phonenumber, CV etc)
employer_details_tabel; (name, address, companyname, phone, etc)
than 2 more tables, one for the jobs jobseekers have applied for, and one for the jobs employers have posted - as employers are likely to post more than one job position, and jobseekers and likely to apply for many different jobs, so;
jobs_applied_table; (id, jobid, status, etc)
employer_posted_jobs; (jobid, position_details, date_posted, status, etc)
hope that helps / gives you something to think about.
good luck
//Table 1
$table = "CREATE TABLE IF NOT EXISTS questions (
id INT (11) NOT NULL AUTO_INCREMENT,
quesion TEXT NOT NULL,
user VARCHAR (255) NOT NULL,
date TIMESTAMP NOT NULL,
question TEXT NOT NULL,
answer TEXT NOT NULL,
PRIMARY KEY (id)
)";
//Table 2
$table = "CREATE TABLE IF NOT EXISTS answers (
id INT (11) NOT NULL AUTO_INCREMENT,
user VARCHAR (255) NOT NULL,
answer TEXT NOT NULL,
datum TIMESTAMP NOT NULL,
PRIMARY KEY (id)
)";
I have two forms. One for inserting question and other for inserting answers. It's working. But i have a problem. It is normal that for one question you have few answers, but right now when i submit answer, and try to add second answer for first question, it overwrite me first answer.
//this code do that
$sql="UPDATE questions SET answer='$_POST[answer]' WHERE id='$_POST[id]'";
I now - it is obviously that every inserted answer do to the table 'questions', but i need to insert answers into table 'answers' and every answer to be connected for his question from table 'question'
So, resume - user come to the site, see The question, answer on it and leave, after come second user and give answer for same question and also leave..
How to make it work. I've trying with some foreign keys, but nothing..
Add an extra field, lets say for ex. QuestionId to your answser table.
In your insert SQL u provide the QuestionId to your answser insert statement.
Then u can select all your answers for one question with :
SELECT * FROM answser WHERE QuestionId=$qId
Question:
What is the correct syntax to use when selecting a column value into an UPDATE/INSERT trigger NEW variable?
Details:
Here are the [simplified] tables I am using as well as the query. For the purposes of this example I have chosen something that is recursive, in this case a comment (ie. one can comment on a picture, but also on the comment). At any given time I want to know what picture a comment is commenting on, but I don't want to query the table n times to get to that picture (hence why I am rejecting the Adjacency List Model), so I have a trigger on insert to copy the target picture over.
PICTURES table:
CREATE TABLE IF NOT EXISTS pictures
(
id INT NOT NULL AUTO_INCREMENT,
PRIMARY KEY ( id )
)
COMMENTS table:
CREATE TABLE IF NOT EXISTS comments
(
id INT NOT NULL AUTO_INCREMENT,
picture_id INT NOT NULL,
comment_id INT NOT NULL,
PRIMARY KEY ( id ),
FOREIGN KEY ( picture_id ) REFERENCES pictures ( id ),
FOREIGN KEY ( comment_id ) REFERENCES comments ( id )
)
COMMENTS trigger: Note that NEW.comment_id and NEW.picture_id are NOT NULL, therefore, they default to zero (FALSE). In my actual program I have an XOR to reject invalid attempts to assign both a picture and a comment id.
CREATE TRIGGER bi_comments_fer BEFORE INSERT ON comments FOR EACH ROW
BEGIN
IF ( NEW.comment_id )
THEN
select NEW.picture_id := picture_id from comments where id = NEW.comment_id;
END IF;
END
I tried including an # sign, like so
select #NEW.picture_id := picture_id from comments where id = NEW.comment_id;
But that also raised a syntax error. Can anyone tell me how to fix this?
SET NEW.picture_id := (SELECT picture_id FROM comments WHERE id = NEW.commend_id);
Bret Taylor discussed the SchemaLess Design in this blog post: http://bret.appspot.com/entry/how-friendfeed-uses-mysql
It looks like they stored different class's Objects into only one table.Then build more index tables.
my question is that how to build index on one class.
for example, a user's blog is {id,userid,title,body}. A user's tweet is {id,userid,tweet}.
If I want to build an index for users' blogs how can I do?
It's very simple -- perhaps simpler than you expect.
When you store a blog entity, you're going to insert to the main entities table of course. A blog goes like this:
CREATE TABLE entities (
id INT AUTO_INCREMENT PRIMARY KEY,
entity_json TEXT NOT NULL
);
INSERT INTO entities (id, entity_json) VALUES (DEFAULT,
'{userid: 8675309,
post_date: "2010-07-27",
title: "MySQL is NoSQL",
body: ... }'
);
You also insert into a separate index table for each logical type of attribute. Using your example, the userid for a blog is not the same as a userid for a tweet. Since you just inserted a blog, you then insert into index table(s) for blog attribute(s):
CREATE TABLE blog_userid (
id INT NOT NULL PRIMARY KEY,
userid BIGINT UNSIGNED,
KEY (userid, id)
);
INSERT INTO blog_userid (id, userid) VALUES (LAST_INSERT_ID(), 8675309);
CREATE TABLE blog_date (
id INT NOT NULL PRIMARY KEY,
post_date DATETIME UNSIGNED,
KEY (post_date, id)
);
INSERT INTO blog_date (id, post_date) VALUES (LAST_INSERT_ID(), '2010-07-27');
Don't insert into any tweet index tables, because you just created a blog, not a tweet.
You know all rows in blog_userid reference blogs, because that's how you inserted them. So you can search for blogs of a given user:
SELECT e.*
FROM blog_userid u JOIN entities e ON u.id = e.id
WHERE u.userid = 86765309;
Re your comment:
Yes, you could add real columns to the entities table for any attributes that you know apply to all content types. For example:
CREATE TABLE entities (
id INT AUTO_INCREMENT PRIMARY KEY,
entity_type INT NOT NULL,
creation_date TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
entity_json TEXT NOT NULL
);
The columns for entity_type and creation_date would allow you to crawl the entities in chronological order (or reverse chronological order) and know which set of index tables matches the entity type of a given row.
They do not store objects of different classes in the same table. The 'entities' table they are referring to is used to store only one kind of entities.
For example, a typical entity in FriendFeed might look like this:
"id": "71f0c4d2291844cca2df6f486e96e37c",
"user_id": "f48b0440ca0c4f66991c4d5f6a078eaf",
"feed_id": "f48b0440ca0c4f66991c4d5f6a078eaf",
"title": "We just launched a new backend system for FriendFeed!",
"link": "http://friendfeed.com/e/71f0c4d2-2918-44cc-a2df-6f486e96e37c",
"published": 1235697046,
"updated": 1235697046,
To understand the implementation better, have a look at the example given here: https://github.com/jamesgolick/friendly#readme