I'm writing what should be a fairly straightforward SQL query for a modification of the IMDB database; it's supposed to return a list of all films that are categorized as BOTH horror and comedy, which I've done by creating a list of horror, a list of comedy, and then deleting everything from one that's not in the other. The query is as follows:
WITH
table_left AS (SELECT primary_names.name AS name, year, genre, title_id
FROM titles NATURAL JOIN primary_names NATURAL JOIN title_genres WHERE genre = 'Horror'),
table_right AS (SELECT primary_names.name AS name, year, genre, title_id
FROM titles NATURAL JOIN primary_names NATURAL JOIN title_genres WHERE genre = 'Comedy')
DELETE FROM table_right WHERE (title_id NOT IN (SELECT table_left.title_id))
SELECT name, year FROM table_right;
However, this generates an "ERROR: syntax error at or near 'SELECT'" on the last line of the query. I'm fairly new to SQL, but have gone over the syntax multiple times and checked some guides and I just can't understand what's going wrong. There shouldn't be a comma after the DELETE FROM statement, I don't think I've got a comma in any inappropriate places...it may be staring me in the face, but I'm at a loss, and would love to hear any suggestions.
When you use the WITH syntax, you can declare multiple table expressions, but then you can follow it with just one SQL query.
But you have two — a DELETE followed by a SELECT, with no statement terminator between the two statements. This doesn't match any syntax rule of SQL.
I could comment that another way to achieve what you want, listing films that are in two categories, is to do a self-join.
SELECT p.name, t.year, t.title_id
FROM titles AS t
INNER JOIN title_genres AS g1 ON t.title_id = g1.title_id AND g1.genre = 'Horror'
INNER JOIN title_genres AS g2 ON t.title_id = g2.title_id AND g2.genre = 'Comedy'
INNER JOIN primary_names AS p ON t.title_id = p.title_id
You really need to learn how to use JOIN if you're coding with SQL. Not doing so is like using another language like Java or Ruby without understanding loops. I don't mean joins are like loops, just that joins are a foundational part of the SQL language, and you need to know how to use them.
Related
I am quite an amateur with SQL (I am a teacher rather than programmer) and have written some code which worked in SQLITE but does not work in MYSQL. I have a table called 'scores' of student names, exercises and scores. As well as returning the completed exercises, I also wish to return those which are not completed. For this I used CROSS JOIN to generate all combinations of student and exercise. In SQLITE this returned null values for students that had not completed a particular exercise, which is useful.
Using this code in MYSQL, it complains that "Every derived table must have its own alias"
I understand this means that a subquery must have an 'AS ...' term. However, no matter where I add it, I still receive that error. I have tried online SQL 'validators' to help me, but still no success.
Can anybody help improve my code please ? Thank you
SELECT othertable.name , othertable.exercise, scores.score
from ((select distinct name from scores)
CROSS JOIN (select distinct exercise from scores)) AS othertable
left join scores
on(scores.name = othertable.name AND scores.exercise = othertable.exercise )
order by othertable.name, othertable.exercise
The problem with your code is what the error says, in MySql you must set an alias for each subquery of your query.
But instead of aliasing the 2 cross joined subqueries and the result of their join, drop the parentheses of the subqueries and use 3 aliases:
SELECT n.name, e.exercise, s.score
FROM (SELECT DISTINCT name FROM scores) AS n
CROSS JOIN (SELECT DISTINCT exercise FROM scores) AS e
LEFT JOIN scores AS s
ON s.name = n.name AND s.exercise = e.exercise
ORDER BY n.name, e.exercise
In this database
https://www.databasestar.com/sample-database-movies/
I would like to make the following query: "List the name and genre of all the actors in the film Brazil".
I make this query:
USE movies;
SELECT DISTINCT p.person_name AS 'Nombre', g.gender AS 'Sexo' FROM movie m
JOIN movie_crew mc ON m.movie_id = mc.movie_id
JOIN department d ON mc.department_id = d.department_id
JOIN movie_cast mc2 ON m.movie_id = mc2.movie_id
JOIN person p ON mc2.person_id = p.person_id
JOIN gender g ON mc2.gender_id = g.gender_id
WHERE m.title = 'Brazil' AND d.department_name = 'Actors';
But no results appear and I don't understand where is my mistake.
Thanks.
I recommend you simplify the schema somewhat.
Just use simple strings for genre, language_role, keyword, gender, person_name
Use iso_code in place of country_id
Perhaps simple abbreviations for department and company
These do need normalizing (as you have don): person, movie, company, but mostly because there is other stuff in those entities.
That is, get rid of most of the tables in the leftmost and rightmost columns.
Once you have made that change, the error may mysteriously go away. (And, when you get more data, the queries will run faster. This does assume you have suitable indexes.)
I have two sql queries and I need the intersect between then. I know mysql does not have the intersect operand, so how could I do it? Tried some solutions I found online but they all return some syntax error. The queries are:
SELECT person_name FROM person NATURAL JOIN (
SELECT * FROM movie NATURAL JOIN role WHERE movie_name = 'Alien'
) alias1
SELECT person_name FROM person WHERE gender = 'f'
You can JOIN all three tables together, and apply both WHERE clauses.
Here is an example. It assumes that your movie table joins to your role table on a column called movie_id, as well as an assumption that you have a person_id column in role and person to join them. You'll need to change this query to use the columns that your tables use.
SELECT
p.person_name
FROM
movie m
INNER JOIN role r
ON (m.movie_id=r.movie_id)
INNER JOIN person p
ON (r.person_id=p.person_id)
WHERE
m.movie_name='Alien'
AND p.gender='f'
Edit: I've used INNER JOIN here, with a guess at the columns to join on, as opposed to keeping the OP's NATURAL JOIN. As the comments to the OP have mentioned, best practice is to explicitly identify the joins, and not rely on a NATURAL JOIN.
I've got 3 tables: book, publisher, book_category
For a particular book category (fantasy) I have to display list of publisher names supplying that genre.
publisher_name and category_name are linked through book table, so my query is:
SELECT publisher.publisher_name
FROM publisher, book, book_category
WHERE publisher.publisher_id = book.publisher_id
AND book.category_id = book_category.category_id
AND category_name = 'fantasy';
But the result I'm getting is repeating the name of publisher if there's more than one fantasy book supplied by that publisher.
Let's say I've got The Hobbit and The Lord of the Rings,both are fantasy and are supplied by the same PublisherA.
In that case the result of my query is:
PublisherA
PublisherA
Is it possible to get that result just once? Even if there's much more than 2 fantasy books
published by the same publisher?
Just use distinct if you only need publisher_name
SELECT distinct publisher.publisher_name
by the way, try to use JOIN syntax... to join tables
SELECT distinct p.publisher_name
FROM publisher p
join book b on b.publisher_id = p.publisher_id
join book_Category bc on bc.category_id = b.category_id
where bc.category_name = 'fantasy'
Use DISTINCT
SELECT DISTINCT publisher.publisher_name
FROM publisher, book, book_category
WHERE publisher.publisher_id = book.publisher_id
AND book.category_id = book_category.category_id
AND category_name = 'fantasy';
Try adding this to the end of the query: GROUP BY publisher.publisher_name
Everyone is mentioning DISTINCT, which is correct (better than GROUP BY in MySQL, because of the way the optimizer is set up), but I figured I would also add a modification for performance enhancements.
Currently you have implicit cross joins to get to the other tables, and making these explicit INNER JOINs will increase efficiency because of the order of filtering. Example:
SELECT DISTINCT Publisher.publisher_name
FROM publisher Publisher
INNER JOIN book Book ON Publisher.publisher_id = Book.publisher_id
INNER JOIN book_category Book_Category ON Book.category_id = Book_Category.category_id
WHERE Book_Category.category_name = 'fantasy';
In the original query, you bring in the complete record set of all three tables (publisher, book, book_category), and then from that set you join on the respective keys, and then return the result set. In this new query, your join to Book_Category happens based only upon the record set returned from the join between Publisher and Book. If there is filtering that happens based on this join, you will see a performance increase.
You also have the added benefit of being ANSI-compliant, as well as explicit coding to improve ease of maintenance.
I have two tables one called games and one called reviews.
I am trying to join these two tables together and have looked through the documentations and also the other questions here on stackoverflow.
SELECT games.id, games.title, games.developer, reviews.review, reviews.review_title,
(SELECT review, COUNT(*)
FROM reviews
GROUP BY review) AS Numberofreviews
FROM games
INNER JOIN reviews
ON games.ean=reviews.games_ean;
The query that i am trying to make is to get a table that shows the list of games and how many reviews each game has recieved.
But when i try implementing the above code i get the error operand should contain one column
Ive looked at other people getting this error but not in the same situation.
Any help would be apprecatied
edit: this is with mySQL
You need to use the correlated subquery and for the error it clearly says there should be one column from your subquery
SELECT
g.id,
g.title,
g.developer,
(SELECT
COUNT(*)
FROM
reviews
WHERE games_ean = g.ean) AS Numberofreviews
FROM
games g
INNER JOIN reviews r
ON g.ean = r.games_ean ;
You get the error "operand should contain one column" because your subquery returns two columns. Only one is allowed in this situation. However you don't need a subquery at all. Make a left join (in case for no reviews) and aggregate the reviews:
SELECT games.*, COUNT(reviews.games_ean)
FROM games
LEFT JOIN reviews ON reviews.games_ean = games.ean
GROUP BY games.ean;
I assume that games.* is functional depended on games.ean (i.e. games.ean is unique).
As this statement seems to cause confusion I want to emphasize that a projection on non aggregated attributes in a grouped statement is only defined for attributes which are functionally depended on the the grouped attributes. The statement (given the assumption that games.ean is unique) therefore is valid and makes perfect sense!
MySQL allows projections of non aggregated attributes which are not functionally depended! However they are not defined in ANSI-SQL nor are they deterministic as MySQL selects one undefined value for each non aggregated attribute.
You should move the subquery into the from clause, instead of reviews to get the number:
SELECT g.id, g.title, g.developer, r.Numberofreviews
FROM games g inner join
(SELECT games_ean, COUNT(*) as Numberofreviews
FROM reviews
GROUP BY games_ean
) r
on g.ean = r.games_ean;
It does not make sense to have a column called review_title, because there might be more than one review.
The query that i am trying to make is to get a table that shows the list of games and how many reviews each game has recieved.
SELECT games.id, games.title, games.developer, COUNT(DISTINCT reviews.*) as reviews_amount
FROM games
LEFT JOIN reviews ON games.ean = reviews.games_ean
GROUP BY games.ean;