Ms Access | Issues with INNER JOIN query - sql

So, I'm doing a movie database and I got one table for actors and one table for movie titles.
In the Movies table I got Three columns for Actors. Actor_1, Actor_2, Actor_3. In these fields, I only write numbers which corresponds to a row in the Actors table.
Each actor have these columns:
Actor_ID, Firstname, Surname
Now if I do this query:
SELECT movie.titel, firstname + ' ' + surname AS name
FROM Movie
INNER JOIN Actors ON movie.actor_1=actor.actor_id
Then I get almost what I want. I get the movie titles but only one actor per movie. I don't know how I am supposed to do for the movies where I got two or three actors.
I had to translate to code so it would be more understandable. The code in its original shape works so don't mind if it's not 100% here. Just would appreciate some pointers on how I could do.

You need to change your table design to include a junction table. So you will have
Movies
ID
Etc
Actors
ID
Etc
MoviesActors
MovieID
ActorID
Etc
Your query might be:
SELECT m.MovieTitle, a.ActorName
FROM Actors a
INNER JOIN (Movies
INNER JOIN MoviesActors ma
ON m.ID = ma.MovieID)
ON a.ID = ma.ActorID
Relational database design
Junction tables

Related

Complex SQL Query with Dead Ends and 7 Tables

I was tasked with creating a complex query that incudes all of the data from all of the tables minus the Keys. I am having an issue with the dead end tables and how to circle back around to include the data of the connecting table. I need to select columns DivisionName, ProgramName, ProgramChairFName, ProgramChairLName, CourseID, OutcomeDescription from the listed tables.
SQL Diagram
The 'dead-ends' aren't really dead-ends. When you join all the tables by the appropriate keys, you'll get an assembly of the information you want.
Consider a really simple example:
table person
id name
1 Alice
table pet
id person_id animal
1 1 cat
table hobby
id person_id activity
1 1 dancing
Here, the two tables pet and hobby link to the person table via the person_id key.
In your thinking, "pet" could be considered a "dead-end" because it doesn't link to hobby. But it doesn't need to. The query:
SELECT name, animal, activity
FROM person
JOIN pet ON person.id = pet.person_id
JOIN hobby ON person.id = hobby.person_id;
creates the correct joins back to the person table. It's not a linear path (person -> pet -> hobby). The nature of the joins are specified by the "ON" part of the query. You can see this simple example works here: http://sqlfiddle.com/#!9/02c94b/1
So, in your case, you can have a series of JOINs:
SELECT [all the columns you want]
FROM Division d JOIN Program p
ON d.DivisionKey = p.DivisionKey
JOIN ProgramChairMap pcm
ON p.ProgramKey = pcm.ProgramKey
JOIN ProgramChair pc
ON pcm.ProgramChairKey = pc.ProgramChairKey
JOIN Course c
ON p.ProgramKey = c.ProgramKey
JOIN CourseOutcome co
ON c.CourseKey = co.CourseKey
JOIN Outcome o
ON co.OutsomeKey = o.OutcomeKey

SQL Statement querying same table 2 times

Ok, I've got brain cells melting at an alarming rate on this SQL statement. Not my database, but I've been tasked with extracting data. So here's what I'm dealing with...
It is medical data. We have a database where ALL of the people are listed in one table- patients, as well as doctors. Each person has a unique PersonID. Let's just start with the Person table:
Person:
PersonID, PersonType, LastName, FirstName
I have another table that is hospital admissions.
Admissions:
AdmissionID, PersonID and PrimaryMD
where the Primary MD is the same as the Person ID for a doctor.
I need to extract each Admission, with the last name, and then the first name of the patient, but then I need to go back, based on the PrimaryMD identifier and use that value to pull the last name and first name of the doctor so that my results look like:
Admission | PatientLastName | PatientFirstName | DoctorLastName | DoctorFirstName
Ultimately, I'll need to pull address information for both the patient, and the doctor which is all stored in an address table with the same PersonID as in the person table, and then pull the doctor's address using the primarymd against the person table. But I can't figure how to write two queries in the same statement against these similar columns. I tried using aliases, and some left and inner joins and even a union, but I can't seem to get things right.
Any assistance would be hugely appreciated.
Try this:
SELECT
a.AdmissionID,
pat.LastName AS PatientLastName,
pat.FirstName AS PatientFirstName,
doc.LastName AS DoctorLastName,
doc.FirstName AS DoctorFirstName
FROM Admissions a
INNER JOIN Person pat
ON a.PersonID = pat.PersonID
INNER JOIN Person doc
ON a.PrimaryMD = doc.PersonID
For getting addresses use the same steps:
SELECT
a.AdmissionID,
pat.LastName AS PatientLastName,
pat.FirstName AS PatientFirstName,
doc.LastName AS DoctorLastName,
doc.FirstName AS DoctorFirstName
FROM Admissions a
INNER JOIN Person pat
ON a.PersonID = pat.PersonID
INNER JOIN Person doc
ON a.PrimaryMD = doc.PersonID
INNER JOIN Addresses addPat
ON pat.PersonID = addPat.PersonID
INNER JOIN Addresses addDoc
ON doc.PersonID = addDoc.PersonID

SQL needed for a model

I have tables with data on actors, directors and movies separately but i need to find a way to input a director and output a list of all the actors that have worked with that director and all of the films those actors have been in. As this could be a very long list, they also need to limit the results in some sensible way. I have the SQL code to give out list of directors and the actors they have worked with and the movies the actor has been in with the director but we need all the movies the actors have worked in including the ones without that director?
Movie Table
Movie_ID Title Director Release Date
1 A John 2015
Actor Table
Actor_ID Actor_Name
if that's the structure that you have, I think you need a foreign key in the MovieTable to be able to relate the actors with the movies they have worked in. or a diferent table where you have the ID of actors and movies they have worked in, in that way you should do something like this:
SELECT actor_name, title, director
FROM MovieTable m
inner join actorTable a
on m.movieID = a.actor_name
WHERE m.director = "yourImput"
LIMIT (0,10) --limit that only displays 10 rows
Mmmm.. I'm not sure of the data structure partially posted in comments, but aren't you looking for something like this ?
SELECT Title FROM Movie m, Acts a, Actors ac
WHERE m.Movie_ID = a.Movie_ID
AND a.Actor_ID = ac.Actor_ID
AND m.Director='the name you are looking for';

SQL: How do I find which movie genre a user watched the most? (IMDb personal project)

I'm currently working on a personal project and I could use a little help. Here's the scenario:
I'm creating a database (MS Access) for all of the movies myself and some friends have ever watched. We rated all of our movies on IMDb and used the export feature to get all of the movie data and our movie ratings. I plan on doing some summary analysis on Excel. One thing I am interested in is the most common movie genre that each person watched. Below is my current scenario. Note that the column "const" is the movies' unique IDs. I also have individual tables for each person's ratings and the following tables are the summary tables that make up the combination of all the movies we have watched.
Here's the table I had: http://imgur.com/v5x9Dhg
I assigned each genre an ID, like this: http://imgur.com/aXdr9XI
And here is a table where I have separate instances for each movie ID and a unique genre: http://imgur.com/N0wULo8
I want to find a way to count up all of the genres that each person watches. Any advice? I would love to provide any additional information that you need!
Thank you!
You need to have at least one table which has one row per user and const (movie watched). In the 3 example tables you posted nothing shows who watched which movies, which is information you need to solve your problem. You mention having "individual tables for each person's ratings," so I assume you have that information. You will want to combine all of them though, into a table called PERSON_MOVIE or something of the like.
So let's say your second table is called GENRE and its columns are ID, Genre.
Let's say your third table is called GENRE_MOVIE and its columns are Const and ID (ID corresponds to ID on the GENRE table)
Let's say the fourth table, which you did not post, but which is required, is called PERSON_MOVIE and its columns are person, Const, rating.
You could then write a query like this:
select vw1.*, ge.genre
from (select um.person, gm.id as genre_id, count(*) as num_of_genre
from user_movie um
inner join genre_movie gm
on um.const = gm.const
group by um.person, gm.id) vw1
inner join (select person, max(num_of_genre) as high_count
from (select um.person, gm.id, count(*) as num_of_genre
from user_movie um
inner join genre_movie gm
on um.const = gm.const
group by um.person, gm.id) x
group by person) vw2
on vw1.person = vw2.person
and vw1.num_of_genre = vw2.high_count
inner join genre ge
on vw1.genre_id = ge.id
Edit re: your comment:
So right now you have multiple tables reflecting people's ratings of movies. You need to combine those into a table called PERSON_MOVIE or something similar (as in example above).
There will be 3 columns on the table: person, const, rating
I'm not sure if access supports the traditional create table as select query but ordinarily you would be able to construct such a table in the following way:
create table person_movie as
select 'Bob', const, [You rated]
from ratings_by_bob
union all
select 'Sally', const, [You rated]
from ratings_by_sally
union all
select 'Jack', const, [You rated]
from ratings_by_jack
....
If not, just combine the tables manually and add a third column as shown indicating what users are reflected by each row. Then you can run my initial query.

Novice SQL query question for a movie ratings database

I have a database with one table, like so:
UserID (int), MovieID (int), Rating (real)
The userIDs and movieIDs are large numbers, but my database only has a sample of the many possible values (4000 unique users, and 3000 unique movies)
I am going to do a matrix SVD (singular value decomposition) on it, so I want to return this database as an ordered array. Basically, I want to return each user in order, and for each user, return each movie in order, and then return the rating for that user, movie pair, or null if that user did not rate that particular movie. example:
USERID | MOVIEID | RATING
-------------------------
99835 8847874 4
99835 8994385 3
99835 9001934 null
99835 3235524 2
.
.
.
109834 8847874 null
109834 8994385 1
109834 9001934 null
etc
This way, I can simply read these results into a two dimensional array, suitable for my SVD algorithm. (Any other suggestions for getting a database of info into a simple two dimensional array of floats would be appreciated)
It is important that this be returned in order so that when I get my two dimensional array back, I will be able to re-map the values to the respective users and movies to do my analysis.
SELECT m.UserID, m.MovieID, r.Rating
FROM (SELECT a.userid, b.movieid
FROM (SELECT DISTINCT UserID FROM Ratings) AS a,
(SELECT DISTINCT MovieID FROM Ratings) AS b
) AS m LEFT OUTER JOIN Ratings AS r
ON (m.MovieID = r.MovieID AND m.UserID = r.UserID)
ORDER BY m.UserID, m.MovieID;
Now tested and it seems to work!
The concept is to create the cartesian product of the list of UserID values in the Ratings table with the list of MovieID values in the Ratings table (ouch!), and then do an outer join of that complete matrix with the Ratings table (again) to collect the ratings values.
This is NOT efficient.
It might be effective.
You might do better though to just run the plain simple select of the data, and arrange to populate the arrays as the data arrives. If you have many thousands of users and movies, you are going to be returning many millions of rows, but most of them are going to have nulls. You should treat the incoming data as a description of a sparse matrix, and first set the matrix in the program to all zeroes (or other default value), and then read the stream from the database and set just the rows that were actually present.
That query is the basically trivial:
SELECT UserID, MovieID, Rating
FROM Ratings
ORDER BY UserID, MovieID;
Sometimes the best thing to do is refactor the table/normalize your data (if that is an option).
Normalize the data structure:
Users Table: (all distinct users)
UserId, FirstName, LastName
Movies Table: (all distinct movies)
MovieId, Name
UserMovieRatings: (ratings that users have given to movies)
UserId, MovieId, Rating
You can do a Cartesian join if you want every combination of users and movies and then use the UserMovieRatings table as needed.
It's probably best to do the refactoring now before you system gets any more complicated. Take this time upfront and I'm positive any queries you need to make will come naturally...hope that helps...
Sample Query:
select UserId, FirstName, LastName, MoveId, Name, cast(null as int) as Rating
into #FinalResults
from Users
cross join Movies
update #FinalResults
set Rating = UMR.Rating
from #FinalResults FR
inner join UserMovieRatings UMR
on FR.UserId = UMR.UserId and FR.MovieId = UMR.MovieId
If I understand your question correctly, you have all the data in your table, and you just want to extract it in the right order. Is that correct? If so, it should just be a mattter of:
select userid, movieid, rating
from ratings
order by userid, movieid