MySQL: M:N Table Linking Two Tables - mysql

I'm getting ready to populate a couple of tables in a movie database I have created. The Movies table has already been created. It looks like this:
movieid INT NOT NULL PRIMARY KEY
title VARCHAR(50)
link VARCHAR(100)
release_date VARCHAR(10)
It should perhaps be noted that I'm using MySQL-python and Scrapy to populate this data in the MySQL database, but perhaps that doesn't matter.
I have created three additional tables which have not yet been populated: Producers, Actors and Directors. Each of these looks like the other in that there exists id, name and movie title. So Actors looks like:
actorid INT NOT NULL PRIMARY KEY
actor VARCHAR(40)
title VARCHAR(50) <<<<------ This is the movie title from the Movies tables
Now, I would like to create a table called Movie To Actor which holds the movieid from the Movie table and the actorid from the Actor table and not have the title column existing in the Actors table.
I figure there are two ways to do this:
First Way:
Get all of the data into the Actors table with title acting as a foreign key and to THEN create the Movie To Actor table, adding the appropriate ids where movies.title is equal to Actors.title and to then drop the title column from Actors.
Second way:
Do this as I am populating the data. First create the Movie to Actor table, set up key constraints and set this to auto update as the data is added to Actors table. I would prefer this as it makes things significantly easier and I think is stylistically better. Was hoping someone could instruct me on how I would go about doing this. I think I can figure out how to extrapolate instructions in MySQL into MySQL-python, but would need help on how to do the former.

A couple points first off:
Unless you're manually populating the actorid and movieid fields in the actors and movies tables you should have an auto_increment on those columns.
If you're using movies.title to link to anything else, you should add a unique index to that column in the movies table.
You should ultimately drop the title column from the actors table. Otherwise you'll either have multiple rows for the same actor name (redundant) or only one movie per actor (unrealistic).
For the first method you mentioned, you actually can first create the movie_actor table and then populate the existing data:
INSERT INTO movie_actor (movieid, actorid) SELECT movieid, actorid FROM movies INNER JOIN actors ON actors.title=movies.title;
For the second, you can use a trigger:
delimiter //
CREATE TRIGGER add_actor
AFTER INSERT ON actors
FOR EACH ROW BEGIN
SET #movieid = (SELECT movieid FROM movies WHERE title=NEW.title);
IF #movieid IS NOT NULL THEN
INSERT INTO movie_actor (movieid, actorid) VALUES (#movieid, NEW.actorid);
END IF;
END;
//
delimiter ;
I'd suggest option 1 followed by having whatever form you're using to populate these tables to populate the movie_actor table independently (e.g. after adding an actor, you can set whatever movies he/she was in, merely adding a mapping to the movie_actor table). Then if you want to get a list of movies for an actor you can just
SELECT title FROM movie_actor
INNER JOIN movies ON movies.movieid=movie_actor.movieid
WHERE actorid=????

Related

relational databases and auto incrementing

hello i'm trying to make two databases linked for a book review system i'm creating
for example i have a table for books and i also have another table for genres.
The books table will store all the different books and will have a foreign key of the genre it belongs to using a genre_id key or something.
When i do a query for genres i want it to display how many books are in that genre eg 2 books in the fantasy genre.
for that i would need a records column? but how do i have that auto incrementing/deleting when new records are added or deleted?
EDIT:
Wow thanks for all the help so quickly, so i understand i don't need a seperate table for records but say i wanted it to work with this
function all_get() {
$this->load->database();
$sql = 'SELECT * FROM books;';
$query = $this->db->query($sql);
$data = $query->result();
$this->response($data, 200);
}
how would i do the query to show the records each genre has instead of all the seperate books showing individually?
EDIT: I may have misunderstood, initially I thought these are really two separate questions - one on creating an auto incrementing primary key and another on how to show the number of books in each genre.
Counts
On showing the number of books in each genre as well as the name of the genre, I think you're looking for something like this:
SELECT g.genreName, count(*) from books b
JOIN genres g on g.ID = b.genreID
GROUP BY g.genreName
SQL Fiddle: http://sqlfiddle.com/#!2/a3c45e/2
Auto incrementing
As others have already commented, you don't need a separate records table, but in case you still need help with auto incrementing primary keys, here's the most basic example from W3 schools:
CREATE TABLE Persons
(
ID int NOT NULL AUTO_INCREMENT,
LastName varchar(255) NOT NULL,
FirstName varchar(255),
Address varchar(255),
City varchar(255),
PRIMARY KEY (ID)
)
You don't need a records column. You can query how many books are related to each genre:
SELECT count(*) FROM Book WHERE genre_id = :genreId;
BTW before you start you might rethink your entity relations. Is Genre <-> Book really 1:n?

MySql Join Tables with List of Indexes in one table's Column?

I have MySQL database with two tables, Users and Games. Basically each user has a unique ID and a set of games that they are playing and each game table has an ID and HasStarted flag (when HasStarted = false players can join the game). The table was set up so the users list of games a string of ID numbers separated by semi-colons (EX: 1;3;5; means they are part of game 1, 3, and 5). Create examples at bottom
What I would like to do is fetch all the games that are joinable AND that they are not already a part of.
I tried using
SELECT * FROM games INNER JOIN users ON games.GID = users.gamelist
WHERE games.status = 0;
but that only matches the games based on the first game in their list. What I'm going to do for now is just fetch all the joinable games into an array and then get the player's list of games and drop those but I was wondering if there was a way to fetch them all in one query. Does anyone know if I can do something like this?
CREATE TABLE users
(UID INT NOT NULL AUTO_INCREMENT,
PRIMARY KEY(UID),
games TINYTEXT)
CREATE TABLE games
(GID INT NOT NULL AUTO_INCREMENT,
PRIMARY KEY(GID),
has_started BIT)
You REALLY should alter your schema to have a users_to_games table to normalize your data. The setup could look like this:
users
------
uid - primary key
[other fields specific to a single user]
games
------
gid - primary key
has_started
[other fields specific to a single game]
users_to_games
--------------
uid - first field in compound primary key
gid - second field in compound primary key
There would be one record in users_to_games for every game a particular user is involved in.
Now in order to get your list of games that have not started but user has not joined you could do this:
SELECT gid, [any other fields from game table you want for display]
FROM games
WHERE is_started = 0
AND gid NOT IN (SELECT DISTINCT gid FROM users_to_games WHERE uid = ?)

multiple column values in mysql

I need to make a table 'Movies' which will have columns:
ID Title Description Category etc
And another one called 'Movie_Categories' containing, for example
ID Category
1 Action
2 Adventure
3 Triller
but since category in table Movies will have multiple choices what is the correct way to do this?
should i use comma-separated values like someone said in this post Multiple values in column in MySQL or is there a better way?
This is a many-to-many relationship.
You need a join table to make it right, such as :
CREATE TABLE film_category (
category_id int,
film_id int,
PRIMARY KEY (category_id, film_id)
);
DO NOT GO FOR COMMA-SEPARATED VALUES. NEVER.
Having said that. Bear in mind that when you have a so called many-to-many relationship, that is, a relationship where you can have one category with many movies and one movie with many categories, you will always need to generate an additional table.
This table will only need the Primary Keys of each of the other 2 tables and will have a compound key.
So the schema will end up being:
Movies(ID, Title, Description, Category)
Categories(ID, Category)
Movies_Categories(ID_Movie, ID_Category)
In bold are the primary keys.
In order to get all the categories for a movie you will just have to join each of the three tables.
A final comment about having multi-valued fields is that your table will not be in First Normal Form which will, sooner or later, give you lots of headaches.
The last thing to do is have a non normalized table by storing comma separated values.
*You should have a table movies and a table for categories.
You should create a mapping table which will map the movieId to the categoryId*

Linking columns in different tables in MySql / parent-child relation

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.

mysql group by set id

MYSQL Database:
I have a table of data that I need to put into two tables.The one table contains persons and an animal. Every record is a person and an animal. I am chaning this to a multi table database and want to group by the persons name, and then give the group an id (like a customer id) and then in my other table pass the customer ID to the idcustomer to join the two tables. To simplfy this i dont mind if these newly created ids are in the single table with new column names. I can after the fact export them out and import them.
The question really is, how can I create a group by customer name, give that customer and ID and then use that same id in a column to do the join.
To describe the scheme:
I have taken over a project. The database as of now is one table. In this one table is:
persons name, address, childsname, description of child
What would like it to be at least to start with is:
id_person, person name, childsname, childparent, description of child.
The id of the person and the childsparent should be the same. When I break the table down, and put the child information in the child table, the child will have a parent id.
I still plan on having two tables. But I can export and create the tables, my problem is assiging the parent id to the child column with the current data.
An example of a couple rows would be:
person_name, address, childsname, description
mark twain, 23 st., Buckweat, short smart kid
mark twain, 23 st., Daniel, short kinda smart
Instead i would like to have 2 tables, one for the parents and the other table is their children.
The way this database was setup, if one person has more than one child, there is another row that lists all of the same information.
What I have planned is to have multiple tables with a join.
The original database has no index, or unique identifier.
What I want to do is loop through the records, since there is no unique id, if the customer name is identical, meaning they are listed twice, then they must have more than one child.
In that case, i want to be able to go through the database and assign a id for the parents. and also ad another colum called parentid, which will be the child table.
To create the table you need you can use a temporary table - to which you will insert all parent names and give them IDs. Then you can update the existing table:
CREATE TABLE name_to_id (
`id` INT(11) AUTO_INCREMENT,
`name` VARCHAR(256),
PRIMARY KEY (`id`));
INSERT INTO name_to_id (name)
SELECT DISTINCT name FROM my_table;
ALTER TABLE my_table
ADD COLUMN id INT(11) FIRST,
ADD COLUMN parent_id INT(11) AFTER childsname;
UPDATE my_table t
JOIN name_to_id n ON t.name = n.name
SET t.id = n.id, t.parent_id = n.id;
To create the parents and children separate tables you can use:
CREATE TABLE parents AS
SELECT id, name, address FROM my_table
GROUP BY id;
CREATE TABLE children AS
SELECT childsname, parent_id, description
FROM my_table;
You would probably want to ALTER those tables later to add a primary keys and other needed indexes.