How can I rewrite a SQL query without any sub-queries? - sql

How can I rewrite this query without using any subqueries in SQL?
I'm not too familiar with how to do this, but I think it's done by using "join."
SELECT title
FROM Movies Old
Where year < ANY
(SELECT year
FROM Movies
WHERE title = Old. title
);
(Note: this comes from the relation Movies(title, year, length, genre, studioName, producerC#))

To literally rewrite your current query using joins you can try this:
SELECT m1.title
FROM Movies m1
INNER JOIN Movies m2
ON m1.title = m2.title AND
m1.year < m2.year
But if all you really want is to find movie titles which appear more than once, then when not just use a GROUP BY query:
SELECT title
FROM Movies
GROUP BY title
HAVING COUNT(*) > 1

Related

Get Average in SQL Through Join

I'm just playing around with SQL and I'm trying to do the following.
I have 2 tables and here is their structure:
Movies_metadata Movies
ratings table:
Ratings
As there are many ratings for one movie, what I'd like to do is get the avg rating per movie and have it display next to the title which is only available in the Metadata table.
This is as far as I got but obviously the issue with my SELECT statement is that it'll return the average of all movies and display it for each record:
SELECT
(SELECT
AVG(rating)
FROM
`movies-dataset.movies_data.ratings`) AS rating_avg,
metadata.title,
metadata.budget,
metadata.revenue,
metadata.genres,
metadata.original_language,
metadata.release_date
FROM
`movies-dataset.movies_data.Movies_metadata` AS metadata
INNER JOIN `movies-dataset.movies_data.ratings` AS ratings
ON metadata.id = ratings.movieId
LIMIT 10
Here is an example of the result:
Result
I'm thinking I can potentially use a GROUP BY but when I try, I get an error
Appreciate the help!
The following should work:
SELECT movies_metadata.title, AVG(ratings.rating)
FROM movies_metadata
LEFT JOIN ratings ON movies_metadata.id = ratings.movieID
GROUP BY movies_metadata.title
You can swap movies_metadata.title by movies_metadata.id if not unique.
The LIMIT function and GROUP function might conflict with each other. Try getting the average rating as part of the inner join like this:
SELECT
ratings.averagerating,
metadata.title,
metadata.budget,
metadata.revenue,
metadata.genres,
metadata.original_language,
metadata.release_date
FROM `movies-dataset.movies_data.Movies_metadata` AS metadata
INNER JOIN (SELECT movieId, AVG(rating) averagerating FROM `movies-dataset.movies_data.ratings` GROUP by movieId) AS ratings
ON metadata.id = ratings.movieId
ORDER BY ratings.averagerating
LIMIT 5
Maybe try something like:
Select m.movieID, (r.rate_sum / r.num_rate) as avg_rating
From your_movies_table m
Left Join (select movie_id, sum(rating) as ‘rate_sum’, count(rating) as ‘num_rate’
From your_ratings_table
Group by movie_id) r
On m.movie_id = r.movie_id
I'm using a left join because I'm not sure if all movies have been rated at least once.

SQL Collect duplicates to one place? PostgreSQL

Sorry I'm new here and I'm also new with SQL and can't really explain my problem in the title...
So I have a TV show database, and there I have a Genre column, but for a TV show there are multiple Genres stored, so when I'm selecting all my TV Shows how can I combine them?
It needs to look like this:
https://i.stack.imgur.com/3EhBj.png
So I have to combine the string together, here is my code so far what I wrote:
SELECT title,
year,
runtime,
MIN(name) as name,
ROUND(rating, 1) as rating,
trailer,
homepage
FROM shows
JOIN show_genres
on shows.id = show_genres.show_id
JOIN genres
on show_genres.genre_id = genres.id
GROUP BY title,
year,
runtime,
rating,
trailer,
homepage
ORDER BY rating DESC
LIMIT 15;
I also have some other stuff here, that's my exerciese tasks! Thanks!
Also here is the relationship model:
https://i.stack.imgur.com/M89ho.png
Basically you need string aggregation - in Postgres, you can use string_agg() for this.
For efficiency, I would recommend moving the aggregation to a correlated subquery or a lateral join rather than aggregating in the outer query, so:
SELECT
s.title,
s.year,
s.runtime,
g.genre_names,
ROUND(s.rating, 1) as rating,
s.trailer,
s.homepage
FROM shows s
LEFT JOIN LATERAL (
SELECT string_agg(g.name, ', ') genre_names
FROM show_genres sg
INNER JOIN genres g ON g.id = sg.genre_id
WHERE sg.show_id = s.id
) g ON 1 = 1
ORDER BY s.rating DESC
LIMIT 15

What am I missing this? Do I need to use JOIN or UNION or a subquery?

I'm trying to get some practice making queries with SQL.
I'm working with a playground that uses SQLite.
There are two tables:books_north and books_south
Both have columns for: id, title, author, genre and first_published
The query I'm trying is to generate a report that lists the book titles from both locations and count the total number of books with the same title.
I can't work out how to even get started with the count.
So far I have
SELECT title
FROM books_north
INNER JOIN books_south
ON books_north.title = books_south.title;
But it just says that title is an ambiguous column.
How do I do this? Thank you
You need UNION ALL to get the count of each title
Select Title,Count(1) as [Count]
From
(
SELECT title FROM books_north bn
union all
select title from books_south bs
) A
Group by Title
Another approach using FULL OUTER JOIN (If your RDBMS supports)
SELECT COALESCE(bn.Title, bs.title) as title,
( bn.[count] + bs.[count] ) AS [Count]
FROM (SELECT title,
Count(1) AS [count]
FROM books_north
GROUP BY title) bn
FULL OUTER JOIN (SELECT title,
Count(1) AS [count]
FROM books_south
GROUP BY title) bs
ON bn.Title = bs.Title
Regarding your error message, Title column is present in the both the table so when you select the Title column you need to tell the compiler from which table you want to select Title column. It can be done by giving a alias name to the tables in Join
SELECT COUNT( DISTINCT a.title) AS TITLECount
FROM books_north a
INNER JOIN books_south b
ON a.title = b.title;
A simple inner join would be sufficient to get your count. Use a table alias in SELECT to remove the ambiguity of column title as it is present in both the tables.
In regard to the error that you mentioned:
The problem is SELECT title - it asks you to be specific about where title shall be read from, books_north or books_south.
So you need to tell either SELECT book_north.title or SELECT book_south.title, that's all there is regarding the ambiguity error.
The count is explained in the other answers. You need to learn group by if you want to display title and count (it is basically a group by title in your case.
SELECT books_north.title, count(books_north.title)
FROM books_north
INNER JOIN books_south
ON books_north.title = books_south.title
GROUP BY books_north.title;
This works:
SELECT title, COUNT(title) count FROM
(
SELECT title FROM books_north
UNION ALL
SELECT title FROM books_south
)
GROUP BY title;

SQL inner join with count() condition, and relationnal algebra

I have these tables:
Movies (id, name)
Cast (idmovie, actor)
And I would like to count the number of actors for each movie and then only get movies with more than 10 actors. I have a query to count the number of actors for each movie, which goes like this:
SELECT idmovie, count(actor) FROM Cast GROUP BY idmovie HAVING count(actor) > 10;
Now, I wonder how to get that result and join it to the Movies table.
I tried:
SELECT name FROM Movies INNER JOIN (SELECT idmovie FROM Cast GROUP BY idmovie HAVING count(actor) >2) Cast ON Cast.idmovie = Movies.id;
But it doesn't work.
I also have to translate it to relational algebra.
π name (σ (count(σ id = idmovie))) Movies⨝Cast
Which is obviously wrong...
Any help?
Try this...
SELECT m.name, COUNT(c.actor) AS 'ActorsCount'
FROM Movies m INNER JOIN [Cast] c ON m.id = c.idmovie
GROUP BY m.name HAVING COUNT(c.actor) > 10;
The query looks correct to me except perhaps that you aliased the nested query with Cast which is also the name of a table. I'm not sure what effect that'd have but I'd expect it to confuse MySQL. Try the following:
SELECT name FROM Movies INNER JOIN
(SELECT idmovie FROM Cast GROUP BY idmovie HAVING count(actor) >2) CastCount
ON CastCount.idmovie = Movies.id;
I didn't try it, but I think that'll work

How do I do this SQL query

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 movies that have no ratings. I am new to the SQL language and can't quite see how this can be done. From what I have been told this is a relatively simple query.
SELECT * FROM Movie WHERE Movie.mid NOT IN (SELECT mID FROM Rating)
There are three ways to do this. My preference is for an Anti-Join, which is a LEFT JOIN with a where clause test for IS NULL on the right side of the join.
SELECT *
FROM
Movie
LEFT JOIN Rating
ON moive.Mid = rating.mid
WHERE
rating.mid is null
select * from movie where mID not in (select mId from rating)
You can use the NOT EXISTS clause. A good example for Oracle is at http://www.dba-oracle.com/sql/t_subquery_not_in_exists.htm. The syntax may vary depending on your database