I have 4 tables as follows which has the following attributes:
Actor:actor_id,firstname,lastname
film_actor:actor_id,film_id
film_category:film_id,category_id
category:category_id,name
I want to find the list of all actors working in films, their film_id, category_id and category name.
I want to use the In clause for foll query. So i am getting the o/p by implementing this as follows:
select a.first_name,a.actor_id,fc.film_id,c.name,c.category_id
from actor a,film_actor fa,film_category fc,category c where a.actor_id
in (select fa.film_id from film_actor fa where fa.actor_id=a.actor_id
and fa.film_id
in (select fc.film_id from film_category fc where fc.film_id=fa.film_id
and fc.category_id
in(select fc.category_id from category c where c.category_id=fc.category_id)))
But suppose now i want to know list of actors for particular category_id.Lets say suppose 5
which is present. So I make following changes:
select a.first_name,a.actor_id,fc.film_id,c.name,c.category_id
from actor a,film_actor fa,film_category fc,category c
where a.actor_id in
(select fa.film_id from film_actor fa where fa.actor_id=a.actor_id
and fa.film_id
in (select fc.film_id from film_category fc where fc.film_id=fa.film_id
and fc.category_id
in(select fc.category_id from category c where c.category_id=fc.category_id
and category_id=5)))
I am getting empty result.Also lastly when we should use IN clause and when should we not?
Don't use IN for this.. use JOIN instead.
select
a.first_name,
a.actor_id,
fc.film_id,
c.name,
c.category_id
from
actor a join
film_actor fa on fa.actor_id = a.actor_id join
film_category fc on fc.film_id = fa.film_id join
category c on c.category_id = fc.category_id and c.category_id = 5
I typically only use IN for a hard-coded set of IDs... JOIN or EXISTS for every other case. Not only is this cleaner, but it will likely result in a better performing execution plan as well.
Please start to use join syntax instead of an IN clause:
select a.first_name,
a.actor_id,
fc.film_id,
c.name,
c.category_id
from actor a
left join film_actor fa
on a.actor_id = fa.actor_id
left join film_category fc
fa.film_id = fc.film_id
left join category c
on fc.category_id = c.category_id
and c.category_id=5
This will return all records from the actor table regardless of if there is a matching record in the other tables.
If you need help learning JOIN syntax here is a great visual explanation of joins
Related
I am trying to put together a query from the Sakila database.
The query should find all actors that have starred in all 16 film categories.
To get all of this information into one table for querying, I have performed a INNER JOIN:
SELECT a.first_name, a.last_name FROM actor a
INNER JOIN film_actor fa
ON fa.actor_id = a.actor_id
INNER JOIN film_category fc
ON fc.film_id = fa.film_id;
However, from there I do a GROUP BY on the category_id but don't know how to iterate through and count if a particular actor_id has all 16 categories?
Does this complex of a query require writing a FUNCTION or PROCEDURE?
You are almost there. Group against the actor name and check that the unique category count is 16:
SELECT a.actor_id, a.first_name, a.last_name
FROM actor a
INNER JOIN film_actor fa ON fa.actor_id = a.actor_id
INNER JOIN film_category fc ON fc.film_id = fa.film_id
GROUP BY a.actor_id, a.first_name, a.last_name
HAVING COUNT(DISTINCT fc.category_id) =
(
SELECT COUNT(DISTINCT category_id)
FROM film_category
)
Hey guys I'm new to SQL and having some difficultly. I'm hoping someone could clear some stuff up for me.
This is my issue. I want to display all of the categories that an actor has played in and the amount of films they have played in that category. So for example they have played in action movies 5 times. This is what I have so far:
SELECT c.name AS "Category_Name"
, Count(c.name) AS "Count"
FROM category c
JOIN film_category fc
ON c.category_id = fc.category_id
JOIN film f
ON fc.film_id = f.film_id
JOIN film_actor fa
ON f.film_id = fa.film_id
JOIN actor a
ON fa.actor_id = a.actor_id
WHERE a.first_name = "Kevin"
AND a.last_name = "Bloom"
GROUP
BY c.name
ORDER
BY c.name ASC;
This will display all of the categories and the amount of times "Kevin Bloom" has played in each however it will not display NULL values for categories he has not played in and I need it to. I have spend a few hours trying to figure this out but it either didn't help or I wasn't able to understand it.
From what I gather the WHERE clause is causing this issue. I also believe I will likely need to use a LEFT JOIN instead and possibly a sub query. I'm a little shaky on both of these things when used in conjunction. If anyone can offer some help to a first time learner I would really appreciate it!
SELECT c.name AS "Category_Name", Count(a.actor_id) AS "Count"
FROM category c
LEFT JOIN film_category fc ON c.category_id = fc.category_id
LEFT JOIN film f ON fc.film_id = f.film_id
LEFT JOIN film_actor fa ON f.film_id = fa.film_id
LEFT JOIN actor a
ON fa.actor_id = a.actor_id
AND a.first_name = 'Kevin' AND a.last_name = 'Bloom'
GROUP BY c.name
ORDER BY c.name ASC;
Per your comment, why to use AND versus WHERE is about how WHERE is evaluated when executing. The WHERE clause limits the entire result set by the condition(s) you specify. Whereas the ON conditions only limit what is allowed to match the records and not necessarily the entire results set when an OUTER JOIN is used. So If you put a WHERE condition in that limits results based on the RIGHT side of your LEFT JOIN it becomes and INNER JOIN because it tells SQL that you only want the results that match and because only some categories match that actor you would only get those categories. However by putting the condition in the ON clause of the JOIN your results are not limited and all categories will be returned but only actors matching your criteria will be considered.
You would use a LEFT JOIN, but you have to be careful:
SELECT c.name AS Category_Name, Count(a.actor_id) AS "Count"
FROM category c LEFT JOIN
film_category fc
ON c.category_id = fc.category_id LEFT JOIN
film f
ON fc.film_id = f.film_id LEFT JOIN
film_actor fa
ON f.film_id = fa.film_id LEFT JOIN
actor a
ON fa.actor_id = a.actor_id AND a.first_name = 'Kevin' AND a.last_name = 'Bloom'
GROUP BY c.name
ORDER BY c.name ASC;
Notes:
LEFT JOIN is key to the solution.
Notice the COUNT() has changed to count the id from actor. This will return 0 for categories where he has not acted.
The standard delimiter for strings in SQL is a single quote, not a double quote.
There is no need to escape column aliases, unless necessary.
Hello I'm currently working on SQL problem that I can't quite figure out. Here is the Schema I'm working with:
Here is the question I am stuck on:
-- 3 Find the first name, last name and total combined film length of Sci-Fi films for every actor. That is the result should list the names of all of the actors (even if an actor has not been in any Sci-Fi films) and the total length of Sci-Fi films they have been in.
So far I have
SELECT actor.first_name, actor.last_name, (SELECT SUM(film.length)
from film
INNER JOIN film_category
ON film.film_id = film_category.film_id
INNER JOIN category
ON film_category.category_id = category.category_id
INNER JOIN film_actor
ON film_actor.film_id = film.film_id
INNER JOIN actor
ON film_actor.actor_id = actor.actor_id
WHERE category.name = 'Sci-fi'
)
from actor
I know I need to group it by actor_id but i'm unable to do this in a select subquery. Anyone have some tips?
There is no need to use a subquery. Aggregate functions work on the entire data set. The 'group by' specifies how to group the data you're aggregating.
select a.actor_id, a.first_name, a.last_name, sum(f.length)
from actor a
left outer join film_actor fa on fa.actor_id = a.actor_id
left outer join film f on f.film_id = fa.film_id
left outer join film_categories fc on fc.film_id = f.film_id
left outer join categories c on c.category_id = fc.category_id
where c.name = 'sci-fi'
group by a.actor_id
;
The outer joins ensure actors with no sci-fi film experience are included in the results by
I don't understand what are you need subquery, try this:
SELECT actor.first_name, actor.last_name,SUM(film.length)
from film
INNER JOIN film_category
ON film.film_id = film_category.film_id
INNER JOIN category
ON film_category.category_id = category.category_id
INNER JOIN film_actor
ON film_actor.film_id = film.film_id
INNER JOIN actor
ON film_actor.actor_id = actor.actor_id
WHERE category.name = 'Sci-fi'
GROUP BY actor.actor_id;
This should get you exactly what you want, including the part about having actors that aren't in Sci-Fi movies. You can LEFT JOIN on film to include all films the film_actor is in. The additional AND statement works with the LEFT JOIN to include actors not in Sci-Fi movies for your aggregate sum function.
SELECT a.actor_id, a.first_name, a.last_name, sum(f.length) AS length
FROM actor a
INNER JOIN film_actor fa ON fa.actor_id = a.actor_id
INNER JOIN film_category fc ON fc.film_id = fa.film_id
INNER JOIN category c ON c.category_id = fc.category_id
LEFT JOIN film f ON f.film_id = fa.film_id
AND c.name = 'Sci-Fi'
GROUP BY a.actor_id;
The top answer here actually is not correct. This will work:
SELECT T1.first_name, T1.last_name, T2.total
FROM
(SELECT a.first_name, a.last_name, a.actor_id
FROM actor a
)
AS T1
LEFT JOIN
(SELECT a.first_name, a.last_name, a.actor_id, SUM( f.length ) AS total, c.name
FROM actor a, film_actor fa, film f, film_category fc, category c
WHERE c.category_id = fc.category_id
AND fc.film_id = f.film_id
AND a.actor_id = fa.actor_id
AND fa.film_id = f.film_id
AND c.name = 'sci-fi'
GROUP BY a.actor_id)
AS T2
ON T1.actor_id = T2.actor_id;
It takes all actors, and combines them with the sci-fi actors and gives the combined screen time for sci-fi movies for all. Test it on your data set, worked for me.
Listed below is my code. It returns the count of each category that a person has been in for a movie. It returns the result but I would like it to list every category including the ones with 0 counts. I tried every combination of LEFT JOIN, OUTER JOIN, etc and it still doesn't work. Any help would be appreciated!
SELECT c.name, COUNT(f.title) FROM category c
LEFT JOIN film_category fc ON c.category_id = fc.category_id
INNER JOIN film f ON fc.film_id = f.film_id
INNER JOIN film_actor fa ON f.film_id = fa.film_id
INNER JOIN actor a ON fa.actor_id = a.actor_id
WHERE a.first_name = 'Jack' AND a.last_name = 'Daniel'
GROUP BY c.name ASC;
Try this. SQL Fiddle demo
SELECT c.name, COUNT(f.title) FROM category c
LEFT JOIN film_category fc ON c.category_id = fc.category_id
LEFT JOIN film f ON fc.film_id = f.film_id
LEFT JOIN film_actor fa ON f.film_id = fa.film_id
LEFT JOIN actor a ON fa.actor_id = a.actor_id and a.first_name = 'Jack' AND a.last_name = 'Daniel'
WHERE 1=1
GROUP BY c.name ASC;
Union the inverse criteria of your query, eg
SELECT c.name, COUNT(f.ti....
...
UNION
SELECT c.name, 0
FROM category c
...
WHERE NOT(a.first_name = 'Jack' AND a.last_name = 'Daniel')
...
I'm having a really hard time translating a piece of MySQL-code to Access.
I'm trying to use one of the queries found in the Sakila (MySQL) Database for an Access project I'm working on.
First of all, the GROUP_CONCAT function doesn't work at all. After some Google searches I found out that Access doesn't support this function but I couldn't find a working alternative. CONCAT however could be replaced by a few '+' operators.
Then comes the triple LEFT JOIN which kept returning a missing operator error. I found a blog post explaining how a series of brackets could help, but this resulted in even more trouble and prompted me to remove the brackets after which it threw more missing operator errors.
Also, SEPARATOR doesn't seem to be accepted as well, but this could be due to GROUP_CONCAT not functioning.
Is there anyone willing to get me in the right direction? I've been struggling with this for way too long.
SELECT
a.actor_id,
a.first_name,
a.last_name,
GROUP_CONCAT(DISTINCT CONCAT(c.name, ': ',
(SELECT GROUP_CONCAT(f.title ORDER BY f.title SEPARATOR ', ')
FROM film f
INNER JOIN film_category fc
ON f.film_id = fc.film_id
INNER JOIN film_actor fa
ON f.film_id = fa.film_id
WHERE fc.category_id = c.category_id
AND fa.actor_id = a.actor_id
)
)
ORDER BY c.name SEPARATOR '; ')
AS film_info
FROM
actor AS a
LEFT JOIN film_actor AS fa ON a.actor_id = fa.actor_id
LEFT JOIN film_category AS fc ON fa.film_id = fc.film_id
LEFT JOIN category AS c ON fc.category_id = c.category_id
GROUP BY a.actor_id, a.first_name, a.last_name
The most commonly-cited Access alternative to the MySQL GROUP_CONCAT() function is Allen Browne's ConcatRelated() function, available here.
As for parentheses around JOINs, yes, Access SQL is fussy about those. Instead of
FROM
actor AS a
LEFT JOIN film_actor AS fa ON a.actor_id = fa.actor_id
LEFT JOIN film_category AS fc ON fa.film_id = fc.film_id
LEFT JOIN category AS c ON fc.category_id = c.category_id
try
FROM
(
(
actor AS a
LEFT JOIN
film_actor AS fa
ON a.actor_id = fa.actor_id
)
LEFT JOIN
film_category AS fc
ON fa.film_id = fc.film_id
)
LEFT JOIN
category AS c
ON fc.category_id = c.category_id