This question already has answers here:
SQL query return data from multiple tables
(6 answers)
Closed 6 years ago.
I have a problem here. I created a database with different tables. I have a table named "movie" with 108 movies. This table includes columns
"id, name, director, year, country",
table named "reviews" which includes columns
"movie_id" (movie_id links to the id of movie which was reviewed),
"review_score" (1 to 5 points),
"review (with review text)",
"critics_id" (which links to the critics from critics-table),
and also table named "critics" which icludes columns
"critics_name" and "critics_id".
The problem is that there is over 100 movies but only 10 of them are reviewed and I have to list only reviewed movies but reviews and movies are in different tables. When I try simple command SELECT name, review FROM movie, reviews - I get a huge list with repeating movies (see on picture) my table
Is there any command which could list only reviewed movies and so that every reviewed movie would be in the list only once?
Thanks beforehand!
This is where you use a join. You'd select from the movie table and join the reviews table, then filter by movies that have a joined review.
For example:
SELECT movie.*, review.review_score, review.review
FROM movie
LEFT JOIN reviews AS review
ON review.movie_id = movie.movie_id -- assuming this column name is correct...
WHERE review.movie_id IS NOT NULL
You could also add another join to your critics table:
SELECT movie.*, review.review_score, review.review, critic.critics_name
FROM ....
LEFT JOIN critics AS critic
ON critic.critics_id = review.critics_id
WHERE critic.critics_id IS NOT NULL
Please note that this example uses left join to highlight the way that the join works, in that if it doesn't find a match then the joined result will be null.
If you used an inner join instead, you wouldn't get any results that don't match the on clause, and as such you wouldn't need the WHERE id IS NOT NULL parts at all.
An inner joined example of the above would return movies that are reviewed, as well as the critic's name:
SELECT movie.*, review.review_score, review.review, critic.critics_name
FROM movie
INNER JOIN reviews AS review
ON review.movie_id = movie.id
INNER JOIN critics AS critic
ON critic.critics_id = review.critics_id
Also - I'm using AS to alias the plural table names to a singular name purely for semantic reasons. You could continue to use reviews and critics if you wanted to without the AS aliases.
Hope below query helps you:
SELECT
m.name,
c.critics_name,
r.review_score,
r.review_text
FROM movies m
JOIN reviews r ON r.movie_id = m.id
JOIN critics c ON c.critics_id = r.critics_id
for distinct movies change query as below:
SELECT DISTINCT m.name
FROM movies m
JOIN reviews r ON r.movie_id = m.id
JOIN critics c ON c.critics_id = r.critics_id
Related
I am newish to SQL and Join statements and I am way out of my league at the moment
I currently have 6 Database Tables that are all linked to the main 7th table based on the main tables ID, however all the information in the other 6 tables are looped and so have several displayed results to the one main tables ID.
Is it possible to join them all into one Join Statement so I can have a results so that everyones information from the main table also shows their information from the 6 other linked tables
So basically when they all have the informationed joined I want to be able to Display all information on a webpage
so I was wondering do I need to do multiple JOIN statements or just one Longer one?
I have Included some Images below that explain it visually. See examples 1 and 2
The columns that are highlighted in yellow are looped to have many results:
2. This is the example of how the information is looped into the
database where there are many Race_id sharing to the same inf_id:
Im not so sure how it will look once it has been joined since some of the information is looped into many Id's and not sure if that means it need to duplicate the column or the rows?? any help would be greatly appreciated.
You could use left join eg for the first tables influencer, social, activities
select i.*, s.follower, s.Social_Medial_URL, a.activity, a.result
from influencer i
left join social s on s.inf_id = i.id
left join activities a on a.inf_id = i.id
you can procede yourself adding the left join for the others tables using the same rules
select i.*
, s.follower_count
, s.social_media_url
, a.compete_activity
, a.compete_results
from influencers i
left join inf_other_social s on s.inf_id = i.id
left join inf_compete_activity a on a.inf_id = i.id
LIMIT 0, 25
I think you are confused about primary key and foreign key. the picture you have given is clearly elaborate everything. as per your db diagram the query might be like this...
select * from
Influencer i
Left Join Social s on i.inf_id = s.inf_id
Left Join Owned_Equip o on i.inf_id=o.inf_id
Left Join Ages_Interacted a on i.inf_id = a.inf_id
Left Join Activities ac on i.inf_id = ac.inf_id
Left Join Awards aw on i.inf_id = aw.inf_id
Left Join History h on i.inf_id = h.inf_id
By using this above query you can get all the information of Influencer and related to him (Social,Owned_Equip,Activities,Award etc) whether they exists or not. If you using only "Join" not "Left Join" then you can only find those records which is common for a single influencer to it's related entities/tables which might you say. as an example: say Influencer (id = 1 , suppose name is dan) after inner join we can get only records related to dan ( his social,owned equipments,activites,awards and so on if those tables contains record related to dan record)
Similar question here
Very similar to the question above but with a slight difference, I need to find a list of users that haven't seen at least one film in a list of movies.
Assuming two tables 'movies' and 'users', there's an n:m relationship between those, and a table 'seen' describing that relationship.
I need to find out for any number of given users, and any number of given movies all the users, from that given list, that have not watched at least one of the given movies.
Is this achievable in a single query? I can't figure out a way of do that.
Edit: Here's a demo with an attempt to solve the problem, the issue with that is it returns users that not have seen all of the movies from the given list. What we need is a user that has not seen ANY of the movies from that list: http://rextester.com/DEIH39789
This query should give you your desired result. I'm assuming your basic structure is:
users (id int, name varchar(20));
movies (id int, title varchar(20));
seen (user_id int, movie_id int);
SELECT u.*
FROM users u
LEFT JOIN seen s
ON s.user_id = u.id AND s.movie_id IN (movielist)
WHERE s.user_id IS NULL AND u.id IN (userlist)
The WHERE s.user_id IS NULL condition means the LEFT JOIN gives you all the users who have not seen any of the movies in movielist, and the u.id IN (userlist) then restricts the results to only that set of users.
You would modify the IN clauses to match the list of movies and users you were interested in. I've made a small demo on Rextester.
Update
I had misinterpreted the question; the desired result is for users who have not seen one (or more) of the movies in the list. This query solves that problem:
SELECT u.*
FROM musers u
LEFT JOIN seen s
ON s.user_id = u.id AND s.movie_id IN (1, 2)
WHERE u.id IN (1, 2, 3)
GROUP BY u.id
HAVING COUNT(s.movie_id) < 2
The result of the JOIN and WHERE is users (1, 2, 3) and the movies they have seen. If they have seen all of the movies in the movie list (1, 2), the COUNT of movies in seen will be 2, otherwise, if they have not seen one (or more) it will be less than 2. Here's an updated demo. Note that when the length of the movie list changes, the 2 in the HAVING clause must change to match the length of the movie list.
considering a n:m relationship between Users and Movies table, with intermediate table Seen.
SELECT * FROM Users u WHERE NOT EXISTS (SELECT UserId FROM Seen s WHERE s.UserId = u.ID)
this query will return Users which does not have any related record in Seen table
I would say something like a left-joining the users-table to the seen-table (and join that table to the movies-table).
(edited the code due to a comment from MatBailie)
Add the list-restritctions in the JOIN-clause (and not the WHERE-clause as MatBailie pointed out to me) and you get something like (Code below should work on SQL-Server but something similar should work for MySql as well):
SELECT COUNT(Users.ID)
FROM Users
LEFT JOIN Seen ON Users.ID = Seen.UserID AND Users.something IN (list)
LEFT JOIN Movies ON Seen.MovieID = Movie.ID AND Movies.something IN (list)
WHERE Movies.ID IS NULL
GROUP BY User.ID -- <-- This is probably optional
But as there are usually multiple ways to get the same result, the adjusted version of my previous answer:
SELECT COUNT(Users.ID)
FROM Users
LEFT JOIN Seen ON Users.ID = Seen.UserID
LEFT JOIN Movies ON Seen.MovieID = Movie.ID
WHERE (Users.something IN (list) OR Users.something IS NULL)
AND (Movies.something IN (list) OR Movies.something IS NULL)
AND Movies.ID IS NULL
GROUP BY User.ID -- <-- This is probably optional
Third attempt: Get all user-ids in list that have seen one of the movies. Next, get all user-ids in list and subtract the user-ids that have seen one of these movies. Know that for large data sets (a couple of thousand is not large) this query might become slow. To test it I've removed "userid = 2 and movieid = 3" from the list of seen, else I would not get a result. Now I see that Nick has not seen any of the first three movies (referring to your rextester example)
SELECT *
FROM musers
WHERE musers.id IN (1,2,3)
AND musers.id NOT IN (
SELECT musers.id
FROM musers
JOIN Seen ON musers.ID = Seen.UserID
JOIN Movies ON Seen.MovieID = movies.ID
WHERE movies.id IN (1,2,3) )
Using the ER diagram of IMBD I need to find the time period in which each actor was active, by listing the earliest and the latest year in which the actor starred in a film, but only for the actors that have starred in at least 10 movies.
I wrote the part in regards to the period of acting, but am struggling with at least 10 movies one. I understand I should use HAVING COUNT
My answer so far is:
SELECT r.actor_id, min(m.year), max(m.year)
FROM roles r
LEFT JOIN movies m ON r.movie_id = m.id
GROUP BY r.actor_id
Try the following. As pointed out my Barmar you don't need the left join.
SELECT r.actor_id, min(m.year), max(m.year)
FROM roles r
GROUP BY r.actor_id
Having count(*) >= 10
In case if you ever have to change the table structure for roles to include the scenario of a single actor performing multiple roles then you might have to change your query like below:
SELECT r.actor_id, min(m.year), max(m.year)
FROM roles r
GROUP BY r.actor_id
Having count(distinct r.movie_id) >= 10
I got the following database layout. The table on the left - the "exhibit" is somehow the parent. The one in the middle - the "flyer" table describes some data about the exhibit and is therefore linked to it by ex_ID. Let's say it's like versioning. Only the latest "flyer" (the highest ID) is important. On the right side you got "text" parts that reference a row in the "flyer" table directly.
So here's the question. How can I retrieve in ONE statements all flyers a) with the highest ID to a non-archived exhibit and that are b) referenced by non-archived text-parts. For example, as shown in the picture, ID 1 and 4 of the flyer-table should not be returned.
For a SQL expert, this might be an easy question. But for all others, that's learning. So, please, no down-voting.
This statement returns only flyers with the highest id by exhibition, that are referenced by a non archived exhibition and have either not archived parts or no referenced parts at all:
SELECT
f.id fid,
f.ex_id,
e.id eid,
e.archived earchived,
p.id pid,
p.archived parchived
FROM
Flyer f
INNER JOIN (
SELECT
MAX(id) max_id
FROM
Flyer
GROUP BY
ex_id
) t
ON
f.id = t.max_id
INNER JOIN
Exhibition e
ON
f.ex_id = e.id
AND
e.archived = false
LEFT JOIN
Part p
ON
f.id = p.fl_id
AND
p.archived = false
;
Explanation
The INNER JOIN to the subselect will give us the highest id of the
Flyer table by Exhibition id.
We use then an INNER JOIN to Exhibiton to get the details of the exhibiton, only if these are not archived
and a LEFT JOIN to the part table to get only those parts that are not archived or non existent.
DEMO
I have a database having the following structure. Each book can have multiple authors, and each author can write multiple books.
[book:book_id, book_name, book_price]
[author: author_id, author_name]
[link:book_id, author_id]
{book_id's and author_id's are linked. the complete structure is shown here: http://i.stack.imgur.com/vIFNU.png}
Now each book has a price (currency). 30% of the price should be equally distributed to each author who have contributed to the book.
My question is how to find the total payment for each author for a particular year.
[I thought of a solution my self. I could do only up to step 1. If you can provide me some hints or materials where I can find how do such manipulations, it would be very helpful]
Algorithm of my solution is:
So for each book_id, I need to find the number of author_id's in the middle table who has the same book_id. (could do it by query)
If I divide the book_price by number_of_author_in_book and multiply it with 30/100, I get the money for that book that will go to the each author's account for that book (say payment_of_one_author_in_book)
For each author_id in the middle table, I look up for the corresponding book_id and add the payment_of_one_author_in_book for that author_id to a new variable (author_payment_this_year) corresponding to the author ID, if the year matches to the query year.
Thanks in advance
This example includes aliases and subqueries.
SELECT
a.author_id,
a.author_name,
SUM(share.auth_share) AS author_total
FROM (link l
INNER JOIN (
SELECT
b.book_id,
( [b.book_price] * 0.3 ) / [no_auth] AS auth_share
FROM book b
INNER JOIN (
SELECT
l.book_id,
COUNT(l.author_id) AS no_auth
FROM link l
GROUP BY l.book_id) AS ac
ON b.book_id = ac.book_id) AS share
ON l.book_id = share.book_id)
INNER JOIN author a
ON l.author_id = a.author_id
GROUP BY a.author_id,a.author_name
SELECT author.AuthorId, author.Author_name, book.Book_Name, book.Book_Price, [Book_Price]/DCount("[Author_id]","[Link]","[Book_id]=" & [Book_Id]) AS Share
FROM (author INNER JOIN link AS link_1 ON author.AuthorId = link_1.Author_id) INNER JOIN book ON link_1.Book_id = book.Book_Id;
Basically, it is just a join of the three tables. The only tricky bit is using DCount function to add up how many authors in Link share this book_ID