Subquery returns multiple rows in HAVING clause - mysql

I want to get the customer who mostly borrowed films of category 3 in 2016, July
SELECT c_firstName, c_lastName, rental.c_ID
FROM customer, rental
GROUP BY rental.c_ID HAVING rental.c_ID=MAX((SELECT COUNT(rental.c_ID)
FROM customer, copies, rentalprocess, rental, film
WHERE customer.c_ID=rental.c_ID AND rentalprocess.r_ID=rental.r_ID AND
rentalprocess.s_ID=copies.s_ID AND film.f_ID=copies.f_ID AND
f_category=3 AND r_date LIKE "2016-07%" GROUP BY rental.c_ID))
But ir doesn't work because it said that the subquery returns more than one row
What can I do?

Max() is an aggregate function that needs to be in a select statement
SELECT
c_firstName
, c_lastName
, rental.c_ID
FROM customer, rental
GROUP BY rental.c_ID
HAVING rental.c_ID=
(
select
MAX(i.iID)
from
(
SELECT
COUNT(rental.c_ID) iID
FROM customer, copies, rentalprocess, rental, film
WHERE
customer.c_ID=rental.c_ID AND
rentalprocess.r_ID=rental.r_ID AND
rentalprocess.s_ID=copies.s_ID AND
film.f_ID=copies.f_ID AND
f_category=3
AND r_date LIKE "2016-07%"
GROUP BY rental.c_ID
) i
)
In this case the sub-select returns multiple rows but then you take the max value of that query
Comment from Mr Linoff is correct, you should use explicity joins:
SELECT
c_firstName
, c_lastName
, rental.c_ID
FROM customer, rental
GROUP BY rental.c_ID
HAVING rental.c_ID=
(
select
MAX(i.iID)
from
(
SELECT
COUNT(rental.c_ID) iID
FROM
customer
inner join rental
on customer.c_ID=rental.c_ID
inner join rentalprocess
on rentalprocess.r_ID=rental.r_ID
inner join copies
on rentalprocess.s_ID=copies.s_ID
inner join film on film.f_ID=copies.f_ID
WHERE
f_category=3
AND r_date LIKE "2016-07%"
GROUP BY rental.c_ID
) i
)

your code should look something like this, join the tables properly in the code.
I dont know wich columns and table would suit best for the solution becuse I dont got your full schema. but this should give faster query. Put more columns in the select if you wish.
select c_firstName | ' ' | c_lastName, count(rental.c_ID) as rentalCustomer
from customer
inner join rental
on join " connect the both tables"
innner join rentalprocess
on "connect rental with rentalprocess"
inner join copies
on " connect rentalprocess with copies"
inner join film
on "connect copies with film"
WHERE customer.c_ID=rental.c_ID AND
rentalprocess.r_ID=rental.r_ID AND
rentalprocess.s_ID=copies.s_ID AND
film.f_ID=copies.f_ID AND
f_category=3 AND r_date LIKE "2016-07%"
group by c_firstName, c_lastName, rental.c_ID
order by rental.c_ID desc;

Related

Write a query to find the full names of customers who have rented sci-fi movies more than 5 times. Arrange these names in the alphabetical order

Hello below is my Code
DB: https://dev.mysql.com/doc/sakila/en/sakila-structure.html
select concat(first_name,' ',last_name) from
customer where customer_id in (
select customer_id from (
select customer_id, count(rental_id) as num
from
category
inner join film_category using(category_id)
inner join film using(film_id)
inner join inventory using(film_id)
inner join rental using (inventory_id)
where name='Sci-Fi'
group by customer_id, rental_id)
where num > 5)T)
when i am executing i am getting the below error
ERROR 1248 (42000) at line 2: Every derived table must have its own alias
Expected Outcome is "full names of customers who have rented sci-fi movies more than 5 times. Arrange these names in the alphabetical order"
Could you please let me know what is the mistake i am doing?
Welcome to SO!
First, it seems like you have 3 opening ( parens and 4 closing ) parens. You should delete the last parenthesis so you have balanced parens.
After that, you want to apply the alias to the deepest level query. (Similar question: What is the error “Every derived table must have its own alias” in MySQL?) You have...
where name='Sci-Fi'
group by customer_id, rental_id)
where num > 5)T)
You probably want...
where name='Sci-Fi'
group by customer_id, rental_id) AS T
where num > 5)
(Don't forget, there is no need for that extra closing paren, so you can see I removed it. It might be part of a bigger query you have, but it doesn't help the standalone code in the question.)
This will stop the immediate error that you're seeing. At least, now on my database, the error I see is: ERROR 1146 (42S02): Table 'db.customer' doesn't exist.
select concat(first_name, ' ', last_name) as Customer_name
from category
inner join film_category
using (category_id)
inner join film
using (film_id)
inner join inventory
using (film_id)
inner join rental
using (inventory_id)
inner join customer
using (customer_id)
where name = 'Sci-Fi'
group by Customer_name
having count(rental_id) > 3
order by Customer_name;
select concat(first_name,' ',last_name) as customer_name from customer
inner join rental
using(customer_id)
inner join inventory
using(inventory_id)
inner join film
using(film_id)
inner join film_category
using(film_id)
inner join category
using(category_id)
where name in ('sci-fi')
group by customer_name
having count(rental_id) > 2
order by customer_name

SQL How to find which customer has rented the most films?

I'm struggling with a question that said Which customer has rented the
most films?
I am doing this using the Seikila sample database in MySQL. I have something that joins my tables together and attempts to give me a count but I know its wrong just looking at the actual data in the rental table.
my code is as below
SELECT r.rental_id, cust.customer_id, count(*) as Total_Rentals
FROM rental as r
INNER JOIN customer AS cust on r.customer_id = cust.customer_id
GROUP BY cust.customer_id;
but it tells me for example customer 1 has rented 32 movies, which I know is wrong. what am I doing wrong?
since I was asked for clarification, the database I am using is:
https://dev.mysql.com/doc/sakila/en/
And I am trying to find which customer has rented the most films, I am not entirely sure what my script is actually returning.
Remove the column rental_id from the select list and sort the result by count(*) descending to return the top 1 row:
SELECT cust.customer_id, cust.name, count(*) as Total_Rentals
FROM rental as r
INNER JOIN customer AS cust on r.customer_id = cust.customer_id
GROUP BY cust.customer_id, cust.name
ORDER BY Total_Rentals DESC LIMIT 1
But if you only need the customer's id then there is no need for a join:
SELECT customer_id, count(*) as Total_Rentals
FROM rental
GROUP BY customer_id
ORDER BY Total_Rentals DESC LIMIT 1
You need to join customer and rental, group by customer id (without rental id) and count it:
SELECT cust.customer_id, count(*) as Total_Rentals
FROM rental as r
INNER JOIN customer AS cust on r.customer_id = cust.customer_id
GROUP BY cust.customer_id;
So this code should work. If it doesn't work, that probably means that you have duplicates or other nonconventional issues.

Find Count of racers from Race Table

I am new to SQL,I have two tables RACER and SPONSOR,
RACER TABLE has these columns
RACER_NAME,
SPONSOR_ID
RACER_ID- Primary KEY
SPONSOR table has these columns
SPONSOR_ID,
SPONSOR_NAME
now I want to find the SPONSOR name and no.of racer associated with that SPONSOR.
Here is what I tried:
select s.sponsor_name , (select count(*) from racer r) where INNER JOIN s.sponsor_id = r.sponsor_id
You need to understand, how JOIN works and its syntax.
select s.sponsor_name, count(*) as total_racer
from
racer r inner join sponsor s
on r.sponsor_id=s.sponsor_id
group by r.sponsor_id
You need to specify both tables in FROM clause, which you were missing.
You could use a join ( left join if not al the sponsor have racer ) and get the result without subselect using group by and count
select s.sponsor_name , count(*)
from SPONSOR s r
left JOIN racer r s.sponsor_id = r.sponsor_id
GROUP BY s.sponsor_name
Your version, with a subquery is reasonable, particularly because in MySQL it can have better performance than the corresponding GROUP BY query. However, it needs to be a correlated subquery. That looks like:
select s.*,
(select count(*)
from racer r
where s.sponsor_id = r.sponsor_id
) as cnt
from sponsor s;
In other words, choose either the JOIN method or the subquery method, but not both for the same value.

Query top ranked values from sum with joins

I have written a query which output the sale figures of all employees, and their name and what shop they work at. But I am trying to find the top sales person for each shop. Can you please explain how can i only show the top sales person for each shop. I was thinking that i can use
SELECT empname, shopname, SUM( rentalrate ) AS Sales
FROM frs_FilmRental
NATURAL JOIN frs_Employee
NATURAL JOIN frs_Shop
GROUP BY empnin, shopname
Here is screenshot of my
Results so far
Here is a really ugly way:
SELECT t1.empname,
t1.shopname,
t2.maxsales
FROM
(
SELECT empname, shopname, SUM(rentalrate) AS sales
FROM frs_FilmRental
NATURAL JOIN frs_Employee
NATURAL JOIN frs_Shop
GROUP BY empname, shopname
) t1
INNER JOIN
(
SELECT t.shopname, MAX(t.Sales) AS maxsales
FROM
(
SELECT shopname, SUM(rentalrate) AS Sales
FROM frs_FilmRental
NATURAL JOIN frs_Employee
NATURAL JOIN frs_Shop
GROUP BY empname, shopname
) t
GROUP BY t.shopname
) t2
ON t1.shopname = t2.shopname AND
t1.sales = t2.maxsales
You will recognize the subquery t1 as simply being your original query. The t2 subquery restricts this result set to only those shops which had the highest sales, implying only the record corresponding to the employeee with the highest sales. In the event of a tie, both records would be returned for that shop.
The query is a bit verbose, but this owes in part to that MySQL does not have support for row number or common table expressions.
SELECT *
FROM
(
SELECT DISTINCT empname, shopname,
SUM( rentalrate ) OVER (PARTITION BY shopname,empname ) AS Sales,
ROW_NUMBER OVER (PARTITION BY shopname,empname ) AS RN
FROM frs_FilmRental
NATURAL JOIN frs_Employee
NATURAL JOIN frs_Shop
GROUP BY empnin, shopname
) X
WHERE X.RN=1

MySql Query Optimisation, replacing not in subquery with join

I have a query that I feel is very bulky and can do with optimisation. First thing would obviously be replacing not in subquery with join but it affects the sub-sub query that I have. I'd appreciate suggestions/workaround on it.
This is the query
SELECT *
FROM lastweeksales
WHERE productID = 1234
AND retailer NOT
IN (
SELECT retailer
FROM sales
WHERE productID
IN (
SELECT productID
FROM products
WHERE publisher = 123
)
AND DATE = date(now())
)
Basically, I want to get rows from lastweek's sales on a product where retailers are not present that did sales today but sales should only be on products by a certain publisher.
:S:S:S
You can group together 2 inner subqueries easily via INNER JOIN. For the outer one you should use LEFT OUTER join and then filter on retailer IS NULL, like this:
SELECT lws.*
FROM lastweeksales lws
LEFT JOIN (SELECT s.retailer
FROM sales s
JOIN products p USING (productID)
WHERE p.publisher = 123
AND s.date = date(now())) AS r
ON lws.retailer = r.retailer
WHERE r.retailer IS NULL;