SQL Multiple Inner Joins on the same field - mysql

I am currently working as a programmer in a small startup aiming on providing pay-per-view content online and I have been assigned to develop the metadata database for the movie catalogue
I have two main tables, movie and people, where *movie_ID* and *people_ID* are the primary keys respectively for each table. Both tables have a many-to-many relationship.
To represent different relations I am currently using link tables, for example, actor_movie would store the *movie_ID* and corresponding *people_ID* for each of the actors in the movie, while the director_movie table would store the *movie_ID* and the director(s) *people_ID*. Same goes for writer, composers and producers.
Now, my problem is that I need to craft out a query that returns all the actors, directors, producers, writers, composers, etc. etc. in one single table to be passed on the frontend Web UI as a list of all the persons involved in the movie.
I'm currently stumped as to how to create a multiple SELECT query that would JOIN all the link tables together based on the *movie_ID* and *people_ID* and then return the details of each of the person in the people table as well.
And example of what I have written so far is:
SELECT
movie.titleMovie,
people.namePeople,
FROM
movie movie
INNER JOIN actorlinkmovie acm ON acm.idMovie = movie.idMovie
INNER JOIN people people ON people.idPeople = acm.idPeople
What I would like to have happen is:
SELECT
movie.idMovie,
movie.titleMovie,
movie.descMovie,
movie.dateMovie,
movie.runtimeMovie,
movie.langMovie,
movie.ratingMovie,
people.namePeople
FROM
htv_movie movie
INNER JOIN htv_actorlinkmovie acm ON acm.idMovie = movie.idMovie
INNER JOIN htv_directorlinkmovie dcm ON dcm.idMovie = movie.idMovie
INNER JOIN htv_producerlinkmovie pcm ON pcm.idMovie = movie.idMovie
INNER JOIN htv_people people WHERE people.idPeople = dcm.idPeople AND people.idPeople = acm.idPeople AND people.idPeople = pcm.idPeople
And it should return the all the related people from a single movie.
Would like to get some input about the whole design since I'm a pretty new at designing a whole database (first time actually) and whether would this design be suitable if I need to scale up to about 5000 movies (the current company aim). This database will pretty much serve as the website's backend as well.
Thanks.
UPDATE: Temporarily worked out a dirty solution using PHP variables and a template SQL query. Looks like doing multiple inner joins wasn't that required after all. Thanks for the suggestions though.

You can achieve your goal like this:
SELECT MovieName,
dbo.GetDirector(MovieID),
dbo.GetActors(MovieID),
dbo.GetWriter(MovieID) FROM Movie
where
dbo.GetDirector(MovieID) is a
function that will return directors
in the movie.
dbo.GetActors(MovieID) is a function
that will return actors in the movie.
dbo.GetWriter(MovieID) is a function
that will return writers in the
movie.
If there are some other tables then you can make functions for those tables as well.
Hope this helps.

Related

Acces, multiple one to one connections question

I have a problem with acces, im trying to make database of airport and cant realy make one to one - one to one - one to one connection beetwen ticket, passanger and luggage. The idea is that one passanger can have one ticket and one luggage, and when im doing it like it is on picture i cant acces luggage from ticket neither from passanger only from luggage itself.
My diagram
Mainly the diagram should be something like:
Simple Data and Keys:
Sample query(all tickets with relevant linked data):
SELECT Tickets.Ticket,
Tickets.Person,
Flights.Flight,
Luggages.Luggage
FROM Flights
INNER JOIN (
(Persons INNER JOIN Tickets ON Persons.ID = Tickets.Person)
LEFT JOIN Luggages ON Tickets.ID = Luggages.ID)
ON Flights.ID = Tickets.Flight;
Second view was the purpose, so it up to your side to do the adjustments.
Note:
Person 3 do not have luggage.
Person 1&2 use same flight.
MS Access was used, but design is not bound to a specific rdbms (only dialects adjustments for a particular implementation)
Also, there is an error on relation Persons-Tickets which should be 1-n.(similar Flight-Tickets).
Still additional constraints could be bound also.
Eg: a person can be just on one flight is a specific time.

Using sakila database to find a movie by language

I'm new to the site and new in sql.
I use a sample database of sakila, I downloaded it from mysql website.
https://dev.mysql.com/doc/index-other.html
I want to find a movie name by its language.
For example I want to find all the movies whose language is their original is English.
I have 2 tables that I use, the movie table and the language table, I JOIN this 2tables, and then return the names of the movies that are in English.
This is what I wrote down, but I can not understand why it does not work for me
Select title from film,language where original_language_id=language.language_id and language.name="ENGLISH";
I get an empty table, even though my movies are in English
Picture of the movie table, language table and query I wrote down:
language table
movie table
query i wrote
I do not understand where the problem is, I think the problem is very small, but I can not find it
It's odd that anything came back with your original query as the original_language_id data is NULL, meaning no data has ever been set. Here is a SQL query that should give you what you need:
SELECT f.`title`
FROM `film` f INNER JOIN `language` l ON f.`language_id` = l.`id`
WHERE l.`name` = 'English';
If you're new to SQL, welcome! Do try to use the proper JOIN style as the method you used has not been actively used for 20+ years.
Cheers,

Matching identical items in different database lists

I'm writing an app where people can upload lists of movies they own.
My database will probably have the following structure:
USER
UserID - unique identifier
Name - user's full name
Email - user's email
MOVIE
UserID - user who owns this movie
MovieID - movie unique identifier (I'm currently using IMDB's code)
So "Movie" has many-to-one relationship with "User"
What I would like to do is to recommend a user of a random "movie buddy". Basically, I would like to find 2 users who own the same movie (so I'm trying to match 2 user's list to find matching movies) and then showing him a message similar to "Hey, XYZ is a fan of The Dark Knight Rises as well!"
The match should be random with a simple filter for already seen suggestions (I don't want a user to get the same suggestion twice for both the same buddy and movie, but it's ok to suggest him the same buddy for a DIFFERENT movie - assuming they both own 2 different movies).
I don't know how to perform this kind of match using MySQL. I'm also open to other suggestion for a database if one is more appropriate (I've heard about graph databases, but never used any myself)
Thanks.
Finding users with the same movie ID is pretty simple its just three JOINs
FROM
User u
INNER JOIN movie m
ON u.UserID = m.UserID
INNER JOIN moive BuddyMovie
ON m.moiveID = BuddyMovie.MovieID
and u.UserID <> Buddy.UserID --Don't want to be your own Buddy
INNER JOIN User BuddyUser
ON BuddyMovie.UserID = BuddyUser.UserID
WHERE
u.UserID = 123 -- For a given user
and m.MovieID = 345 -- Optionally For a given movie
Getting a random user you just need to add ORDER BY RAND()
If you want only two just add LIMIT 2
Making sure you don't get the same Buddy Twice will require that you keep track of which buddies were all ready shown which goes beyond the scope of a single question.

Can I display one to many results in results table?

I have a table for person and a table for language. Each person can speak up to 4 languages. My client wants to search for people that can speak, for instance Spanish.
My problem is that the results table currently won't have a column called Language because they will speak more than one. I could display just the first one, but it will be misleading to hide the other languages that they speak.
The table could have a column for each language, and fill in NULL if they don't have all 4 languages, i.e.:
Language 1
Language 2
Language 3
Language 4
But this seems very sloppy.
I have considered listing all of the languages in a single column, using a comma separated list, but this is know good for sorting the column alphabetically.
Currently, I am having to tell my client that the results table can only show columns where the person has one of them (1 to 1), i.e. name, location, native language etc. Only when the client clicks on that person, can it reveal all of their languages.
Does anyone know if there is a common way to solve this? Hope this makes sense
I do have an association table. The problem is that my search will return
joe bloggs, gotham city, spanish
then
joe bloggs, gotham city, french
on the next row - but then the same person is listed twice in the table. When I restrict it to one entry per name, I just get "joe bloggs, gotham city, spanish". Now I don't know that he also speaks french. Is this clearer?
You should have a join table which contains two fields: person and language. There should be one row per person per language, so if one person speaks four languages, there would be four rows for this user.
The primary key for this table would comprise both fields.
Then to get a list of which people speak Spanish, you would need a query like
select people.name
from people inner join p2l
on people.id = p2l.person
inner join languages
on p2l.language = languages.id
where languages.name = 'Spanish'
And a list of all people who speak a language
select people.name, languages.name
from people inner join p2l
on people.id = p2l.person
inner join languages
on p2l.language = languages.id
And now a list of all people, whether they speak a language or not
select people.name, languages.name
from people left join p2l
on people.id = p2l.person
inner join languages
on p2l.language = languages.id
Having thought about this some more, it seems that you have the following options
Use the simple join/link/association table that both Christophe and I suggested, then massage the data in the program which calls the SQL. This is the simplest route to take.
Maintain a comma delimited list of languages along with the join table. The join table will allow you to answer queries such as 'who speaks Spanish', whereas the list will enable you to print out a list of languages per person. Maintaining this list will be a problem.
Use the 'dedicated field per language' approach of Ravindra; every time you need a new language, you will have to change the field structure, thus this approach is very much not recommended.
Use a cross tab query; this is quite hard to do and depends on which flavour of SQL you are using. Look at this article creating-cross-tab-queries-and-pivot-tables-in-sql.
In my option, option 1 is the best and easiest. SQL is great at what it does and terrible at what it doesn't do, so it's best to take the best parts of SQL and surround them with the best parts of a declarative language.
So the traditional way to solve this is to create something called an association table, which has foreign keys to both the person and language tables. This lets you add an arbitrary number of languages (including zero). Then you can join accross these tables to find all users speaking a specific language.
This may help with how to structure databases: http://en.wikipedia.org/wiki/First_normal_form
There's higher normal forms, but this will help you solve your current problem.
create two table
person having cloumns- person_id,person_name & more if u want.
create another table -Language having columns-person_id,lang1,lang2,lang3,lang4
make person_id as foreign key
now when u want to access languages, just fetch them by compairing person_id
SELECT p.person_id
FROM person p, language l
WHERE p.person_id = l.person_id;

MySQL conditional JOIN using keys from different tables for matching

I have read and learned a lot here, got a lot of problems solved without asking anything so far, but I couldn't cope with this one.
I have three tables:
-programs
->ProgramID (Primary Unique)
->ProgramName
->AuditID
-audits
->AuditID (Primary Unique)
->VenueName
->Address
-events
->EventID (Primary Unique)
->EventDate
->ProgramID
->AuditID
Events are instances of those programs that are on stage that day. Multiple instances of one program might be performed on one day, or none if it's not played. This is basically a temporary table, repopulated daily. Tickets can be bought from programs that are played on said day.
Audits are the actual stages where the plays are performed. A theatre can have several stages.
Programs are plays for theatres that are on their repertoire for years. The last stage where it was is performed is stored for when someone retrieves the information of a program that is not played on the actual day the stage can still be linked.
I am using this query now:
SELECT
programs.ProgramID,
programs.ProgramName,
programs.AuditID,
events.EventID,
events.EventDate,
audits.VenueName,
audits.Address
FROM programs
LEFT JOIN events
ON programs.ProgramID = events.ProgramID
JOIN audits
ON programs.AuditID = audits.AuditID
WHERE programs.ProgramID = :ProgramID
If there is no event of that program the LEFT JOIN gives me information about the program and the audit leaving the event info blank. Good.
Also okay when the event is at the same audit where it was played last time. Great.
The problem is if it's played in a different audit, because the JOIN for the audits table is made based on programs.AuditID key, which is obsolete now.
What I would need is a conditional JOIN, so that when the events.AuditID is not null, the audits table is joined using events.AuditID instead of programs.AuditID.
Thanks in advance!
I believe you should be able to JOIN using IFNULL(events.AuditID, programs.AuditID) to solve this problem...
SELECT
programs.ProgramID,
programs.ProgramName,
programs.AuditID,
events.EventID,
events.EventDate,
audits.VenueName,
audits.Address
FROM programs
LEFT JOIN events
ON programs.ProgramID = events.ProgramID
JOIN audits
ON IFNULL(events.AuditID, programs.AuditID) = audits.AuditID
WHERE programs.ProgramID = :ProgramID