SQL query involving NULL values - sql

The following are the tables I am working with:
Movie (mID, title, year, director)
Reviewer (rID, name)
Rating (rID, mID, stars, ratingDate)
Which statement would I use to display all reviewers that have a NULL value for the date (ratingDate) meaning I need to extract information from both the Reviewer and Rating table.
I have tried different things with the IS NULL command but to no avail. Any help would be appreciated.

SELECT
rev.rID
, rev.name
, rat.mID
, rat.stars
FROM
Reviewer AS rev
JOIN
Rating AS rat
ON rat.rID = rev.rID
WHERE
rat.ratingDate IS NULL

SELECT Reviewer.name
FROM Reviewer
INNER JOIN Rating
ON Reviewer.rID = Rating.rID
WHERE Rating.ratingDate IS NULL
Try this, I think it will do.

it should be trivial
select *
from rating
join reviewer on rating.rid = reviewer.rid
join movie on rating.mid = movie.mid
where ratingdate is null
so there might be other problems - e.g. the ratingdate is not a date and not null but an empty string (ratingdate = '')?

You need to use a LEFT JOIN. That is, a JOIN that includes null values on one side.

Related

SELECT AVG subquery with condition

I have the follwing tables:
teachers , teacher_rating and cities.
teachers has the following columns:
teacherID,location,name,othercities,status
teacher_rating has the following columns:
ratingId, teacherId,content,ratingNumber,created,status,userName
cities has the following columns:
id,name
I'm trying to sort all of the teachers (rows from teachers where status=0) by their average rating, this is my php variable with the SQL:
$q="SELECT
*,
AVG(pr.ratingNumber) AS rating_average
FROM teachers as p
LEFT JOIN teacher_rating pr
ON pr.teacherId = p.teacherID
WHERE p.location=(SELECT `name` FROM `cities` WHERE `id`=:location) AND p.status=0 OR p.othercities REGEXP CONCAT('[[:<:]](', :location,')( |)[[:>:]]') AND p.status=0
GROUP BY p.teacherID
ORDER BY rating_average DESC
";
It works fine, the only problem is that the rating average includes ratings from the teacher_rating table where status=1, I want it to calculate the average rating only using the values from teacher_rating where status=0.
I'm not sure how to approach this problem, thanks for the help!
How about adding pr.status=0 in the join?
ON pr.teacherId = p.teacherID AND pr.status=0
You are mixing AND and OR, so you should use parentheses. I think you intend:
WHERE p.status = 0 AND
pr.status = 0 AND
(p.location = (SELECT `name` FROM `cities` WHERE `id`=:location) OR
p.othercities REGEXP CONCAT('[[:<:]](', :location,')( |)[[:>:]]')
)

Oracle sql - referencing tables

My school task was to get names from my movie database actors which play in movies with highest ratings
I made it this way and it works :
select name,surname
from actor
where ACTORID in(
select actorid
from actor_movie
where MOVIEID in (
select movieid
from movie
where RATINGID in (
select ratingid
from rating
where PERCENT_CSFD = (
select max(percent_csfd)
from rating
)
)
)
);
the output is :
Gary Oldman
Sigourney Weaver
...but I'd like to also add to this select mentioned movie and its rating. It accessible in inner selects but I don't know how to join it with outer select in which i can work just with rows found in Actor Table.
Thank you for your answers.
You just need to join the tables properly. Afterwards you can simply add the columns you´d like to select. The final select could be looking like this.
select ac.name, ac.surname, -- go on selecting from the different tables
from actor ac
inner join actor_movie amo
on amo.actorid = ac.actorid
inner join movie mo
on amo.movieid = mo.movieid
inner join rating ra
on ra.ratingid = mo.ratingid
where ra.PERCENT_CSFD =
(select max(percent_csfd)
from rating)
A way to get your result with a slightly different method could be something like:
select *
from
(
select name, surname, percent_csfd, row_number() over ( order by percent_csfd desc) as rank
from actor
inner join actor_movie
using (actorId)
inner join movie
using (movieId)
inner join rating
using(ratingId)
(
where rank = 1
This uses row_number to evaluate the "rank" of the movie(s) and then filter for the movie(s) with the highest rating.

Creating new instance of subquery with sqlite

Suppose I have the following columns among three tables
Movie
mID | title | year | director
Reviewer
rID | name
Rating
rID | mID | stars | ratingDate
The instructions that I have been given are:
"For all cases where the same reviewer rated the same movie twice and gave it a higher rating the second time, return the reviewer's name and the title of the movie"
The way I have approached this so far is I have done a three way merge of all the tables to capture all the needed information. What I wanted to do next is create an new instance of this three way merge and find where reviewer and movie are equal and where rating is higher. This is what I have so far
SELECT *
FROM (SELECT *
FROM Movie Mov
INNER JOIN Rating Rat
ON Mov.mID = Rat.mID
INNER JOIN Reviewer REv
ON Rev.rID = Rat.rID) A, A table;
WHERE ...
The problem is that I am not able to create a new instance of A. Here I am attempting to do this here A table.
If anyone has any other suggestions on how to better approach this problem that is more clear please let me know.
So, with a problem like this the first task is to find the rows you want. I would do that with a query like this:
select *
from Rating as r1
where exists (
select 1
from rating as r2
where r1.rid = r2.rid
and r1.mid = r2.mid
and r1.stars < r2.stars
and r1.ratingDate < r2.ratingDate
)
Then add the parts you want to fetch (much as you were doing):
select title, name
from Rating as r1
inner join Movie as m on m.mid = r1.mid
inner join Reviewer as z on z.rid = r1.rid
where exists (
select 1
from rating as r2
where r1.rid = r2.rid
and r1.mid = r2.mid
and r1.stars < r2.stars
and r1.ratingDate < r2.ratingDate
)
Here is a fiddle with test data showing it working: http://sqlfiddle.com/#!7/5f0f8/3
Try this:
SELECT v.Name AS Reviewer, m.Name AS Movide
FROM (SELECT DISTINCT A.rID, A.mID
FROM Rating A INNER JOIN Rating B
ON A.rID = B.rID AND A.mID = B. mID
WHERE A.ratingDate > B.ratingDate
AND A.starts > B.starts
) s
JOIN Reviewer v ON v.rID =s.rID
JOIN Movie m ON m.mID = s.mID
I didn't test on Sqlite, however.

sql select actors play two more distinct role in the same movie

the question is to select actors that played 2 or more distinct roles in the same movie.
And I got 3 table, actor (id,name) movie (id,name) and casts(aid,mid,role) (aid is the actor id and mid is the movie id)
I wrote a query like this
select a.name
from actor a, movie m, casts c
where a.id = c.aid and m.id = casts.mid
group by (m.name)
having count(distinct role) > 2;
this didnt print the right result and I didnt see the problem with it.
Thanks for the help!
How about this? Was there any error trying to execute your query?
select actor.name from actor, casts, movie
where casts.aid =actor.id
and casts.mid = movie.id
group by movie.name, actor.name
having count(distinct role) >= 2
As the casts table appears to contain one row per actor, movie, and role (unless you are leaving out other columns), any time a single pair of unique values of aid and mid appears on more than one row, it means the actor played more than one role in that movie. Thus, there is no reason to use distinct. Also because your desired result doesn't contain the movie names, your query doesn't need and shouldn't use the movie table.
If it is true that the cast table has only one row for each unique combination of (aid, mid, and role) then the following should work:
select name
from actor
where id in ( select aid
from casts
group by aid, mid
having count(*) > 1)

Return only unique table id's from MySQL join

I have a MySQL database with two tables (simplified for this question):
movies table columns: id, title, duration, description, created_at, updated_at
rentals table columns: id, movie_id, status, created_at, updated_at
The rental status is either 'CHECKED OUT' or 'RETURNED', so a movie is available if it either has no associated rental, or all of its associated rentals have a status of 'RETURNED'. How do I query available movies? Right now I've got this:
SELECT rentals.id,rentals.status,movies.*
FROM `movies`
LEFT OUTER JOIN rentals ON movies.id = rentals.movie_id
AND movies.kiosk_id = rentals.kiosk_id
WHERE (`movies`.kiosk_id = 1
AND (rentals.id is null or rentals.status != 'CHECKED OUT'));
The problem is this query returns multiple records for a movie if it's been checked out several times, so my ORM gives me duplicate movie objects. Is there some way to specify that I only want unique movie.id's? Should I have some different database schema? Or should I sort it out programatically (seems like it would be too slow)?
I'm not sure what you want with the rentals id, so I took it out.
SELECT
rentals.status, movies.*
FROM movies
LEFT OUTER JOIN (
SELECT
movie_id,
kiosk_id,
-- Because 'CHECKED OUT' comes alphabetically before 'RETURNED',
-- this will have 'CHECKED OUT' if there's at least one rental checked out
MIN(status) AS status
FROM rentals
GROUP BY movie_id, kiosk_id) rentals
ON movies.id = rentals.movie_id
AND movies.kiosk_id = rentals.kiosk_id
WHERE movies.kiosk_id = 1
AND (rentals.id is null or rentals.status != 'CHECKED OUT');
I think you want the distinct rentals.id in your query. try this:
SELECT DISTINCT rentals.id,rentals.status,movies.*
FROM `movies`
LEFT OUTER JOIN rentals ON movies.id = rentals.movie_id
AND movies.kiosk_id = rentals.kiosk_id
WHERE (`movies`.kiosk_id = 1
AND (rentals.id is null or rentals.status != 'CHECKED OUT'));
Why do a LEFT OUTER JOIN? A simple LEFT JOIN should suffice.
You should also move the rentals.status to the ON() bit (I think):
SELECT DISTINCT movies.id, movies.*, rentals.id, rentals.status
FROM `movies`
LEFT JOIN rentals ON (movies.id = rentals.movie_id AND movies.kiosk_id = rentals.kiosk_id AND rentals.status != 'CHECKED OUT')
WHERE `movies`.kiosk_id = 1 AND rentals.id is null
//Edit
You'll also need a distinct
Your problem that you want a result that makes no sense. You want available movies -- that's ok, but what would a rental id mean in the same row with some movie id? You should throw away rentals in SELECT list and after that applying DISTINCT to just movies.id will do the trick
If you need all available movies for rental you can try this:
SELECT movies.*
FROM movies
LEFT JOIN (
SELECT DISTINCT movie_id
FROM rentals
WHERE status!='CHECKED OUT' AND kiosk_id=1) r ON movies.movie_id=r.movie_id