I have these tables:
Movie ( mID, title, year, director )
Reviewer ( rID, name )
Rating ( rID, mID, stars, ratingDate )
and some views:
View LateRating contains movie ratings after January 20, 2011. The view contains the movie ID, movie title, number of stars, and rating date.
create view LateRating as
select distinct R.mID, title, stars, ratingDate
from Rating R, Movie M
where R.mID = M.mID
and ratingDate > '2011-01-20'
View HighlyRated contains movies with at least one rating above 3 stars. The view contains the movie ID and movie title.
create view HighlyRated as
select mID, title
from Movie
where mID in (select mID from Rating where stars > 3)
View NoRating contains movies with no ratings in the database. The view contains the movie ID and movie title.
create view NoRating as
select mID, title
from Movie
where mID not in (select mID from Rating)
Here's my data set : https://prod-c2g.s3.amazonaws.com/db/Winter2013/files/viewmovie.sql
I'm asked to write an instead-of trigger that enables updates to the stars attribute of view LateRating.Here's my approach.
CREATE trigger update_LateRating_title INSTEAD OF
UPDATE OF stars ON LateRating
BEGIN
UPDATE Rating SET stars = stars - 2
WHERE Rating.mID = old.mID
AND Rating.mID IN (SELECT stars FROM Rating WHERE stars > 2);
END;
It gives almost right answer but there is only one wrong row that being 201 101 4 2011-01-27.4 should be 2.What is wrong?
Let's look at your WHERE condition:
...AND Rating.mID IN (SELECT stars FROM Rating WHERE stars > 2)
It states that Rating.mID should be among values of stars selected from rating. I'm unsure what was intended here. Let's assume you want to decrease the number of stars by 2 for any attempt to modify stars (that's weird: you're turning queries which would increase stars into some unrelated queries) if the original number of stars in that line of Rating table was greater than 2.
CREATE trigger update_LateRating_stars INSTEAD OF
UPDATE OF stars ON LateRating
BEGIN
UPDATE Rating SET stars = stars - 2
WHERE Rating.mID = old.mID
AND Rating.stars > 2;
END;
Again, there are many possible interpretations of what you want, and
they all are more or less weird: mID field in LateRating is not
enough to identify the original record in Rating (maybe rID and
mID together would be enough, if you don't allow the same reviewer to
hold different opinions on the same movie simultaneously).
Related
I've been trying to solve an sqlite question where I have two tables: Movies and movie_cast.
Movies has the columns: id, movie_title, and `score. Here is a sample of the data:
11|Star Wars|76.496
62|2001:Space Odyssey|39.064
152|Start Trek|26.551
movie_cast has the columns: movie_id, cast_id, cast_name, birthday, popularity. Here is a sample.
11|2|Mark Hamill|9/25/51|15.015
11|3|Harrison Ford|10/21/56|8.905
11|5|Peter Cushing|05/26/13|6.35
IN this case movies.id and movie_cast.movie_id are the same.
The question is to Find the top ten cast members who have the highest average movie scores.
Do not include movies with score <25 in the average score calculation.
▪ Exclude cast members who have appeared in two or fewer movies.
My query is as below but it doesn't seem to get me the right answer.
SELECT movie_cast.cast_id,
movie_cast.cast_name,
printf("%.2f",CAST(AVG(movies.score) as float)),
COUNT(movie_cast.cast_name)
FROM movies
INNER JOIN movie_cast ON movies.id = movie_cast.movie_id
WHERE movies.score >= 25
GROUP BY movie_cast.cast_id
HAVING COUNT(movie_cast.cast_name) > 2
ORDER BY AVG(movies.score ) DESC, movie_cast.cast_name ASC
LIMIT 10
The answers I get are in the format cast_id,cat_name,avg score.
-And example is: 3 Harrison Ford 52.30
I've analyzed and re-analyzed my logic but to no avail. I'm not sure where I'm going wrong. Any help would be great!
Thank you!
This is how I would write the query:
SELECT mc.cast_id,
mc.cast_name,
PRINTF('%.2f', AVG(m.score)) avg_score
FROM movie_cast mc INNER JOIN movies m
ON m.id = mc.movie_id
WHERE m.score >= 25
GROUP BY mc.cast_id, mc.cast_name
HAVING COUNT(*) > 2
ORDER BY AVG(m.score) DESC, mc.cast_name ASC
LIMIT 10;
I use aliases for the tables to shorten the code and make it more readable.
There is no need to cast the average to a float because the average in SQLite is always a real number.
Both COUNT(movie_cast.cast_name) can be simplified to COUNT(*) but the 1st one in the SELECT list is not needed by your requirement (if it is then add it).
The function PRINTF() returns a string, but if you want a number returned then use ROUND():
ROUND(AVG(m.score), 2) avg_score
product(prod id, product name, product price, product manufacturer)
customer(cust id, customer name, customer address)
rating(prod id, cust id, rating date, rating stars)
Foreign Key: prod id references prod id in product table
Foreign Key: cust id references cust id in customer table
sale(sale id, prod id, cust id, sale quantity, sale cost)
Foreign Key: prod id references prod id in product table
Foreign Key: cust id references cust id in customer table
These schemas represent product information, including sales. Customers can provide ratings for products in a 0 to 5 stars fashion. It is possible for clients to rate the same product more than once.
And here is the question:
For all cases in which the same customer rated the same product more
than once, and in some point in time gave it a lower rating than
before, return the customer name, the name of the product, and the
lowest star rating that was given.
Is there a way to query customers that gave a lower rating before? thank you
This is a rather tricky question. But the answer to your question is EXISTS. The following returns the pairs that have this behavior:
select r.cust_id, r.prod_id
from ratings r
where exists (select 1
from ratings r2
where r2.cust_id = r.cust_id and
r2.prod_id = r.prod_id and
r2.date < r.date and
r2.stars < r.stars
)
Alas, this does not return the minimum stars (because nothing will be before it). One trick is to invert the logic -- so select any rating that has a higher rating following it. The minimum will meet this criterion, so you can do:
select r.cust_id, r.prod_id, min(r.stars)
from ratings r
where exists (select 1
from ratings r2
where r2.cust_id = r.cust_id and
r2.prod_id = r.prod_id and
r2.date > r.date and
r2.stars > r.stars
)
group by r.stars;
I'll let you add the JOINs to get the names.
Consider the following question:
We have 3 tables,
1. Theatre ( theatre_Id, thatre_name )
2. ShowTime ( showTimeId, theatre_Id, movie_id )
3. Movies ( movie_id, movie_name )
Now same movie name can also have different movieId's sort of dependent on the reel.
Eg: [1, HarryPotter], [2, HarryPotter], [3, Pirates of Carr]
Now we need to find movie name which has showtime on all theatre locations ?
Is it nested correlated query ?
If you better phrase the question:
What are the names of movies whose theatre list is the same size as the number of theatres?
you get the query:
select distinct movie_name
from Movies m
where movie_id in (
select movie_id
from ShowTime
group by movie_id
having count(distinct theatre_Id) = (select count(*) from Theatre))
I need to find all titles of films that have greater replacement cost than some R rating film.
film table has...
film_id, title, description, release_year, language_id, original_language_id, rental_duration, rental_rate, length, replacement_cost, rating, special_features, last_update
This is not working...
SELECT
title
FROM film
WHERE replacement_cost > (SELECT
replacement_cost
FROM film
WHERE rating = 'R');
SELECT title
FROM film
WHERE replacement_cost >
(SELECT MAX(replacement_cost)
FROM film
WHERE rating = 'R');
You need aggregation of some kind to make the subselect a scalar value. Using MAX() in your query would give you the highest replacement_cost of a rated R film.
To get the replacement_cost of a particular film then you need to do the same thing but modify your where statement to be the film you want. say you know the film_id then you could do:
SELECT title
FROM film
WHERE replacement_cost >
(SELECT replacement_cost
FROM film
WHERE film_id = 123);
Note I took off MAX() because when using the primary key or criteria that will choose a single scalar value (1 column 1 row) from the table you don't actually have to use aggregation.
Title may not make sense so I will provide some context.
I have a table, call it Movies.
A movie tuple has the values: Name, Director, Genre, Year
I'm trying to create a query that allows me to return all Directors who have never released two consecutive Horror films with more than 4 years apart.
I'm not sure where I'd begin but I'm trying to start off by creating a query that given some specific year, returns the next minimum year, so that I can check if the difference between these two is less than 4, and keep doing that for all movies.
My attempt was:
SELECT D1.Director
FROM Movies D1
WHERE D1.Director NOT IN
(SELECT D2.Director FROM Director D2
WHERE D2.Director = D1.Director
AND D2.Genre = 'Horror'
AND D1.Genre = 'Horror' AND D2.Year - D1.Year > 4
OR D1.Year - D2.Year > 4)
which does not work for obvious reasons.
I've also had a few attempts using joins, and it works on films that follow a pattern such as 2000, 2003, 2006, but fail if more than 3 films.
You could try this:
Select all data, and use lag or lead to return the last or next year. After that look at the difference between the two.
WITH TempTable AS (
SELECT
Name,
Director,
Genre,
Year,
LAG(Year) OVER (PARTITION BY Name, Director, Genre ORDER BY Year ASC) AS 'PriorYear'
FROM
Movies
WHERE
Genre = 'Horror'
)
SELECT
Name,
Director
FROM
TempTable
GROUP BY
Name,
Director
HAVING
MAX(Year-PriorYear) < 2
Try this:
SELECT * FROM (
SELECT director, min(diff) as diff FROM (
SELECT m1.director, m1.year as year1, m2.year as year2, m2.year-m1.year as diff
FROM `movies` m1, movies m2
WHERE m1.director = m2.director and m1.name <> m2.name and m1.year<=m2.year
and m1.genre='horror' and m2.genre='horror'
) d1 group by director
) d2 WHERE diff>4
First, in the inner Select it will list all movie pairs of directors' horror movies with year difference calculated, then minimum of these are selected (for consecutiveness), then longer than 4 years differences are selected...