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;
Related
I have this query I need to optimize further since it requires too much cpu time and I can't seem to find any other way to write it more efficiently. Is there another way to write this without altering the tables?
SELECT category, b.fruit_name, u.name
, r.count_vote, r.text_c
FROM Fruits b, Customers u
, Categories c
, (SELECT * FROM
(SELECT *
FROM Reviews
ORDER BY fruit_id, count_vote DESC, r_id
) a
GROUP BY fruit_id
) r
WHERE b.fruit_id = r.fruit_id
AND u.customer_id = r.customer_id
AND category = "Fruits";
This is your query re-written with explicit joins:
SELECT
category, b.fruit_name, u.name, r.count_vote, r.text_c
FROM Fruits b
JOIN
(
SELECT * FROM
(
SELECT *
FROM Reviews
ORDER BY fruit_id, count_vote DESC, r_id
) a
GROUP BY fruit_id
) r on r.fruit_id = b.fruit_id
JOIN Customers u ON u.customer_id = r.customer_id
CROSS JOIN Categories c
WHERE c.category = 'Fruits';
(I am guessing here that the category column belongs to the categories table.)
There are some parts that look suspicious:
Why do you cross join the Categories table, when you don't even display a column of the table?
What is ORDER BY fruit_id, count_vote DESC, r_id supposed to do? Sub query results are considered unordered sets, so an ORDER BY is superfluous and can be ignored by the DBMS. What do you want to achieve here?
SELECT * FROM [ revues ] GROUP BY fruit_id is invalid. If you group by fruit_id, what count_vote and what r.text_c do you expect to get for the ID? You don't tell the DBMS (which would be something like MAX(count_vote) and MIN(r.text_c)for instance. MySQL should through an error, but silently replacescount_vote, r.text_cbyANY_VALUE(count_vote), ANY_VALUE(r.text_c)` instead. This means you get arbitrarily picked values for a fruit.
The answer hence to your question is: Don't try to speed it up, but fix it instead. (Maybe you want to place a new request showing the query and explaining what it is supposed to do, so people can help you with that.)
Your Categories table seems not joined/related to the others this produce a catesia product between all the rows
If you want distinct resut don't use group by but distint so you can avoid an unnecessary subquery
and you dont' need an order by on a subquery
SELECT category
, b.fruit_name
, u.name
, r.count_vote
, r.text_c
FROM Fruits b
INNER JOIN Customers u ON u.customer_id = r.customer_id
INNER JOIN Categories c ON ?????? /Your Categories table seems not joined/related to the others /
INNER JOIN (
SELECT distinct fruit_id, count_vote, text_c, customer_id
FROM Reviews
) r ON b.fruit_id = r.fruit_id
WHERE category = "Fruits";
for better reading you should use explicit join syntax and avoid old join syntax based on comma separated tables name and where condition
The next time you want help optimizing a query, please include the table/index structure, an indication of the cardinality of the indexes and the EXPLAIN plan for the query.
There appears to be absolutely no reason for a single sub-query here, let alone 2. Using sub-queries mostly prevents the DBMS optimizer from doing its job. So your biggest win will come from eliminating these sub-queries.
The CROSS JOIN creates a deliberate cartesian join - its also unclear if any attributes from this table are actually required for the result, if it is there to produce multiples of the same row in the output, or just an error.
The attribute category in the last line of your query is not attributed to any of the tables (but I suspect it comes from the categories table).
Further, your code uses a GROUP BY clause with no aggregation function. This will produce non-deterministic results and is a bug. Assuming that you are not exploiting a side-effect of that, the query can be re-written as:
SELECT
category, b.fruit_name, u.name, r.count_vote, r.text_c
FROM Fruits b
JOIN Reviews r
ON r.fruit_id = b.fruit_id
JOIN Customers u ON u.customer_id = r.customer_id
ORDER BY r.fruit_id, count_vote DESC, r_id;
Since there are no predicates other than joins in your query, there is no scope for further optimization beyond ensuring there are indexes on the join predicates.
As all too frequently, the biggest benefit may come from simply asking the question of why you need to retrieve every single row in the tables in a single query.
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'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.
I am having a small issue with a simple SQL statement.
I need to find out if I have 7 copies of a movie in the movie table and 6 people have rented it out, I need to see that I only have 1 copy left (I need to do this all through the SQL query). I know normally I would do it using PHP and just takeaway the number hired from the total number of copies, but sadly my college wants me to do it the other way.
SELECT *,
COUNT(distinct hire.movie_id) AS num_orders
FROM `movie`
INNER JOIN hire ON hire.movie_id = movie.id
WHERE num_orders < movie.no_copies;
When I run this I get the following issue #1054 - Unknown column 'num_orders' in 'where clause'.
You can't use an alias in a where predicate - you either need to repeat the predicate, wrap the query in a derived table before filtering on the alias, or you can also use HAVING as per below (in MySql, at least).
I don't see the need for DISTINCT h.movie_id (since you want to count the rentals? - possibly DISTINCT h.hireid ?), and it seems you will need to group by the movies to count the number of rentals.
How about:
SELECT m.id, m.no_copies, COUNT(h.movie_id) AS num_rentals
FROM `movie` m
INNER JOIN hire h ON h.movie_id = m.id
GROUP BY m.id, m.no_copies
HAVING num_rentals < m.no_copies;
I have three tables in MySQL,
groups (key: group_id)
members (key: member_id)
group_member_relations key: group_id, member_id
The last table has combinations of members and groups (members that have joined that group).
I've been struggling with a way to perform a single query that gives me a list of members and groups that are NOT IN the group_member_relations table. (Basically I want to eventually ask the question "What groups is a given member not a member"). I can do this the hard way in code but was wondering if a single query was possible.
Not a SQL wiz at all, but have used it a lot over the last 20 years, mostly basic stuff. This is obviously over my head. Made many attempts over the last few days but, embarrassingly don't seem to get close.
Any pointers from the sql wizards out there..
Groups that a member is not in:
select *
from group
where id not in (
select group_id
from group_member_relations
where member_id = ?)
The following query will list all groups available and the members that are not present on each group. The query will also give all the columns for each table.
SELECT a.*, b.*
FROM members a
CROSS JOIN groups b
LEFT JOIN group_member_table c
ON a.memberID = c.memberID AND
b.groupID = c.groupID
WHERE c.memberID IS NULL OR -- actually this condition is already enough
c.groupID IS NULL
SQLFiddle Demo