I have a topics table that has user generated topics and RSS generated topics but in the existing mySQL database setup, when the RSS feed is inserted into the database, the user generated topic fields are NULL (e.g. topic_title), and when a user adds a topic, the RSS fields in the topic table are NULL (e.g. rss_title and rss_source_name). I also have foriegn keys in the topic table which become NULL (e.g. user_id) when the RSS stream is pulled through - this causes data to fail inserting as user_id is a foriegn key and cannot be NULL. Ideally, I'd like both user generated topics and RSS topics to be stored in the topics table without the fields becoming null, but not sure what would be the best way to structure the existing database (below is an example):
Category table
cat_id
Topic table (Should store all both user generated topics and RSS generated topics)
topic_id
cat_id
topic_title (becomes NULL when RSS feed is inserted into database)
user_id (becomes NULL when RSS feed is inserted into database - this causes data to fail inserting as user_id is a foriegn key and cannot be NULL)
rss_title (becomes NULL when user creates content)
rss_source_name (becomes NULL when user creates content)
Comments table
comments_id
topic_id
comments_title
user_id
Will the topics table have to be separated into two separate tables (one for user generated and one for RSS), but this would cause NULL issues in the comments table. Any advice?
If you want those fields to be null, just declare them to be null! FK constraint checks in SQL treat a null FK as ok.
EDIT part 1 Since user and rss topics both shave titles, just have one field/column instead of two (one for user & one for rss).
If you don't ever want a field to be null then you have to put it in a separate table. Have a table for a user topic topic_id and user_id and another for an RSS topic topic_id and source_name. Then use a table for all topics with columns shared by both user and rss topics, eg topic_id, title, cat_id etc. Each of user and rss topic tables has a topic_id FK to the all topics table. This is standard table subtyping. There are topics, user topics and rss topics.
EDIT part 2 FKs are not columns or pointers. They are constraints. They say that columns' values always appear as other columns' values.
You don't say what the Comments table means. Apparently a user creates a comment, and there is a constraint that its topic_id be of either a user or rss topic_id? Now have a FK to the shared table.
EDIT part 3
Here are the (renamed for clarity) tables per above:
All_topics(topic_id,title,cat_id)
pk (topic_id)
fk (cat_id) references Category (cat_id)
User_topics(topic_id,user_id)
pk (topic_id)
fk (topic_id) references All_topics (topic_id)
Rss_topics(topic_id,source_name)
pk (topic_id)
fk (topic_id) references All_topics (topic_id)
Comments(comments_id,topic_id,comments_title,user_id)
pk (comment_id)
fk (topic_id) references All_topics (topic_id)
If a user_topic or rss_topic row is added or deleted then you add or delete the topic row with its topic_id (which also holds it title).
If you need to keep user/rss titles separate (why??) then there's no all-topic title and topic_title and rss_title go in the user and rss topic tables.
Ideally also some constraints. (Or certain different design styles for table subtyping.)
select topic_id from All_topics = select topic_id from User_topics UNION select topic_id from User_topics
NOT EXISTS (select topic_id from User_topics JOIN USING (topic_id) Rss_topics)
No nulls.
Related
I have a table user it has:
id INT PRIMARY AUTO_INCREMENT
name VARCHAR(30) NOT NULL
Also I have table post
id INT PRIMARY AUTO_INCREMENT
post TEXT NOT NULL
If user visits a certain post I would like to store somewhere in the database that he has already viewed the said post. How would I go about modifying the database to accommodate for that and how would I query for the posts that user has not seen. Should I create a new table to store that info? Or is there some other nifty trick?
The idea is that I simply want a way where if user views the post once he can not view it ever again.
Sorry I am just trying to learn databases and this is one challenge I find quite interesting and difficult.
You will need to implement a many-to-many relationship: a User visits multiple Posts, and a Post is visited by multiple users.
This will take the form of a table with only two columns, each of them being a foreign key to one of your existing tables:
CREATE TABLE user_post_visit (
user_id INT NOT NULL,
post_id INT NOT NULL,
PRIMARY KEY (user_id, post_id),
FOREIGN KEY (user_id) REFERENCES user(id),
FOREIGN KEY (post_id) REFERENCES post(id)
);
Add a record into this table every time a user views a post. In order to find posts that a given user has not viewed yet:
SELECT post.*
FROM post
LEFT JOIN user_post_visit AS upv
ON (upv.post_id = post.id AND upv.user_id = <your user ID here>)
WHERE upv.post_id IS NULL;
Use what RandomSeed has suggested for creating a bridge-table between user and post and then use the following to query out the posts viewed by a user:
SELECT post_id, post FROM user_post_visit, post WHERE user_post_visit.user_id=<user id>
It seems I follow behind #RandomSeed. :D
It seems to me that you want many-to-many relation so you need a new table. How you do it is not strict but for example
Table "read_post" or "unread_post":
user_id, post_id
If the table is unread_post (but you have to create new row to every user when new post created) you can show unread post:
SELECT text FROM post INNER JOIN unread_post ON post.id =
unread_post.post_id WHERE user_id = ?
If table is read_post get unread see RandomSeeds answer.
I have two tables. "users" and "movies". Users table consists of "id"(Auto increment), "name" and "password" columns. There are 2 usernames stored right now. In movies table there are 'title' and 'year' columns. The PHP script allows each user to watch and add new movies to their list. How do I link or make the parent-child relationship or whatever is needed to make it happen in MySQL? Oh, and I also use Adminer. Right now when I log in one user I still see the same movies that I've added with the other user.
If you are stuck with using just two tables as stated in a comment, you have to redesign the Movies table to include a column UserID which identifies which user created that entry. Then you can filter the data so that a user only sees information about the movies they added to the list.
This isn't a good design — the answer by Jeremy Smyth suggesting an extra table to relate movies to users is much more sensible, but you've indicated that isn't allowed. The reason it isn't a good design is that you're going to end up with lots of rows indicating that the same movie was released in the same year, each row entered by a different user, so there is unnecessary repetition. There's also more chance for error; you'll get entries for 'Gone With The Wind' 1938, and 'Gone With The Wind' 1939, and 'Gone With The Wind' 1940 when there should only be one year (1939, as it happens).
Can you please be more specific about what I have to do ...
In the two-tables-only system, you would create the Movies table like this:
CREATE TABLE Movies
(
Title VARCHAR(32) NOT NULL,
Year INTEGER NOT NULL,
UserID INTEGER NOT NULL REFERENCES Users(ID),
PRIMARY KEY(Title, Year, UserID)
);
When you insert a record into this table, you record the ID of the user who did the insertion, so you can query who created which movie records.
If you are actually going to reference this table from elsewhere in the database, you might well add an ID column here, but if there are more tables, then you'd drop the UserID column from this table and create a relationship table:
CREATE TABLE Movies
(
ID INTEGER AUTOINCREMENT PRIMARY KEY,
Title VARCHAR(32) NOT NULL,
Year INTEGER NOT NULL,
UNIQUE(Title, Year)
);
CREATE TABLE Users_Movies
(
MovieID INTEGER NOT NULL REFERENCES Movies(ID),
UserID INTEGER NOT NULL REFERENCES Users(ID),
PRIMARY KEY(MovieID, UserID)
);
Now you can have one record for 'Gone With The Wind' 1939, which might have ID number 207, and twenty different people might list MovieID 207 as one of their movies with 20 simple records in the Users_Movies table.
You will need to create a "many-to-many" relationship between your two tables.
To do this:
First, create an ID column in the Movies table to uniquely identify each one
Then, create another table called user_movies (or "watched" or something useful), that contains the user ID, the movie ID, and any other information you wish to add such as date watched or rating (number of "stars") etc.
Then, whenever a user watches a movie, add a record to the user_movies table to mark the fact that they've done it.
It should be many-to-many, because each user can watch several movies, but each movie can be watched by several users. A "parent-child" relationship isn't appropriate in this case, being a one-to-many relationship.
I want two tables to share a primary auto incrementing id, is this possible? how do i do this? is their anything i need to consider?
the reasons i am doing this, is because it is a better solution than adding groups column to the users table, and also better than creating a completly seperate groups table, because if they share a primary key, i can use the existing posts table for both groups and users. instead of having to create a two distinct posts tables, (group_posts table for group posts. and a user_posts table for user posts.)
existing users table is
id(primary, ai)
username
password
email
my groups table that i want to link to my users table with a shared ai primary key
id(primary, ai, linked to users table id)
group_name
created_by
creation_date
etc.
You should make you schema clearer by doing the following:
Create a table (e.g. people)
id, primary key, auto-increment
type, tells you if it's a user or a group
Make users and groups primary keys foreign keys on people
Insert records in people
Obtain the ID that was assigned using LAST_INSERT_ID()
Insert in users or groups appropriately, using the ID obtained above
Then you'd reference "people", and not "users" or "groups" in your posts table and so on.
Conceptually, thinking of it in an OO way, it means users and groups both extend people.
I'm unsure how to link my tables:
Users(registration details of users),
Personal (personal details of users),
Academic (academic details of users),
Language (language details of users),
Thesis (Thesis details of users),
Referees (Referee details of users),
Addresses (Address details of users)
Should I have an 'id' field in each of the tables so I can join them all? Plus a primary key of of e.g. Academic_ID. Which would I set as auto inc?
Once the users registers, my system should link information from the users table to all other information they enter for the other tables.
I hope this makes sense
thanks
Add a field named "user_id" to your Users table. Then, in each table you wish to join to Users add a field with the same name.
This way, you could make a query like:
select * from Users, Personnal
where Users.user_id = Personnal.user_id
which would join your results the way you want. About your second question, yes you can/should add a unique autoincrement field like personnal_id and so on. Good practice and makes you record unique.
I tend to do an id field as the primary key (autoincrement), then you can do a unique key on lets say user_id (in each table) and then u can use user_id to link the tables.
basically i have this problem i have a table of posts(in my mysql database)
Post{user_id, post, vote_up(int), vote_down(int)}
because users log in, then they get to vote, but i wanted to check if the user has already voted, so then i can not allow them to vote again, and obviously im going to be using user session to control this oppose to tracking ips etc.
so i was thinking do i have to create another table or is thier a better approach.
You will need another table e.g. called "votes":
Vote{user_id, post_id}
I assume, that your "Post" table has a primary key (e.g. "id") that you have not shown in your question above? Then "post_id" should be a foreign key to Post#id.
/Carsten
You'll definately need another table, and some primary and foreign keys would help too:
Post{post_id(int), user_id(varchar), post(clob)}
Votes{vote_id(int), post_id, user_id, up_down(char)}
Your vote_up and vote_down column values are removed and are now calculated with queries:
-- vote_up
select count(*) from votes where post_id = n and up_down = '+';
-- vote_down
select count(*) from votes where post_id = n and up_down = '-';
There should be a unique index on votes(post_id, user_id) to prevent multiple votes by the same user on the same post.
The primary key vote_id does not have to be defined, but each table should have a primary key and if you don't want to use a surrogate key, then you can define the PK using the same columns as above and this will serve as the unique index too, so ot does not have to be defined.