Not sure how to write a simple query - mysql

Hi I Have a table which has number of products and rating for each, due to some reasons I have different row of each product along with rate of each person who rated it, as following:
p1 2
p2 4
p3 4
p1 4
p1 5
p1 3
p2 7
I am using following query but it shows the average rate of all products, but I am expecting it to show the average rate of each product seperately.
Select ProductName, AVG(Rate) FROM Products

Just GROUP BY productName:
Select ProductName, AVG(Rate) AS 'Average Rate'
FROM Products
GROUP BY productName
Edit: To show the one with highest rate:
SELECT ProductName, Rate
FROM Products
ORDER BY rate DESC
LIMIT 1
Edit 2: To get the product name with the highest average rate:
SELECT productname, AVG(rate) Avgrate
FROM Products
GROUP BY productname
HAVING AVG(rate) =
(
SELECT AVG(rate)
FROM Products
GROUP BY productname
ORDER BY AVG(rate) DESC
LIMIT 1
)

You need to add Group By.
Select ProductName, AVG(Rate) FROM Products GROUP BY ProductName
To Sort Result use Order By after Group By
Select ProductName, AVG(Rate) FROM Products GROUP BY ProductName ORDER BY ProductName
Above query sort result in Ascending order if you want to sort descending then use DESC,
Select ProductName, AVG(Rate) FROM Products GROUP BY ProductName ORDER BY ProductName DESC
To Select Higher Rating Product
Select ProductName, AVG(Rate) FROM Products GROUP BY ProductName
HAVING AVG(Rate) = (SELECT MAX(AVG(Rate)) FROM Products GROUP BY ProductName)
This query return all product which have max average rating.
Only One Product with Higher rating use LIMIT in Descending Sort
Select ProductName, AVG(Rate) FROM Products GROUP BY ProductName
ORDER BY ProductName DESC
LIMIT 1

Related

MySQL: Find categories of products whose total price is neither maximum nor minimum?

My data:
product Table:
Category_ID Product_ID Price
1 12 120
1 19 234
2 10 129
3 34 145
3 11 100
4 8 56
I would like to find categories whose total price is neither maximum nor minimum using MySQL.
Results:
Category_ID Total_Price
2 129
3 245
I have found this using the following query, but I would like to know if there is any efficient and better query.
SELECT P.Category_ID, SUM(P.Price) AS Total_Price
FROM Product P
GROUP BY P.Category_ID
HAVING SUM(P.Price)
NOT IN
(
(SELECT MAX(Total) FROM (SELECT SUM(Price) AS Total
FROM Product GROUP BY Category_ID) AS T1),
(SELECT MIN(Total) FROM (SELECT SUM(Price) AS Total
FROM Product GROUP BY Category_ID) AS T2)
)
Thank you.
If you are running MySQL 8.0, you can use window functions to rank the categories by ascending and descending price, then filter:
select *
from (
select category_id, sum(price) as sum_price,
rank() over(order by sum(price)) rn_asc,
rank() over(order by sum(price) desc) rn_desc
from product p
group by category_id
) p
where rn_asc > 1 and rn_desc > 1
In earlier versions, one alternative uses subqueries:
select category_id, sum(price) as sum_price
from product p
group by category_id
having sum(price) > (select sum(price) from product group by category_id order by sum(price) limit 1)
and sum(price) < (select sum(price) from product group by category_id order by sum(price) desc limit 1)
This query would benefit an index on (category_id, price).

How to SELECT based on grouped SUM that is compared to the AVG of that grouped SUM

I have a table consists of films, categories and prices.
Now I want to select only categories with total price (sum of all the price per film under that category) that is higher than the average of those categories' total prices.
I have been able to find the average of the total prices (thanks to this web) but can't combine it together.
Here are the queries:
-- Return the average sums of the price per category
SELECT AVG(sum_price)
FROM
(
SELECT category, sum(price) AS sum_price
FROM film_list
GROUP BY category
) AS inner_query;
-- Return category and its total price
SELECT category, SUM(price)
FROM film_list
GROUP BY category;
--[Error] Return only the category with sums of price larger than the average of sum of prices
SELECT category, SUM(price)
FROM film_list
WHERE SUM(price) >
(
SELECT AVG(sum_price)
FROM
(
SELECT category, sum(price) AS sum_price
FROM film_list
GROUP BY category
) AS inner_query
);
Any help will be much appreciated, thanks!
Try adding group by and then using having
SELECT category, SUM(price)
FROM film_list
GROUP BY category
HAVING SUM(price) >
(
SELECT AVG(sum_price)
FROM
(
SELECT category, sum(price) AS sum_price
FROM film_list
GROUP BY category
) AS inner_query
);
This is most easily solved using window functions:
SELECT c.*
FROM (SELECT category, SUM(price) AS sum_price,
AVG(SUM(price)) OVER () as avg_total_price
FROM film_list
GROUP BY category
) c
WHERE sum_price > avg_total_price

Select an item, total no of times this item is repeated in database and no of times the status of this item is one

I have a products in products table with status broken or not broken.
I need an sql query which show
productid, total no of this this item is in table , times its status was one,
e-g product_id | tottal_no_of_products_oF_this_type | broketn
5 10 | 3
SELECT product_id,
COUNT(product_id) AS duplicate_column, product_status
FROM products_stored where product_status=broken
GROUP BY product_id
ORDER BY COUNT(product_id) DESC;
You are close. You can get the broken ones using conditional aggregation. For example:
select
product_id,
count(*) as total_no_of_products_this_type,
sum(case when product_status = 'broken' then 1 else 0 end as broken
from products_stored
group by product_id
order by count(*) desc
try this :
SELECT product_id,
COUNT(product_id) over(partition by product_status) AS duplicate_column, product_status
FROM products_stored where product_status=broken
ORDER BY 2 DESC;

SQL - Get 10 records, ordered by a column, with some columns being unique

Given a table with a column for timestamps, I want to get the 10 most recent records with particular columns being unique.
How can this be done?
Example:
Data:
purchases
-----------------------------------------------------------------
timestamp first_name last_name customer_id product_name purchase_amount
How can I get the 5 most recent customers who made a purchase, and the product_name and purchase_amount?
Result:
James, Jackson, 1234, 'foo', 432.123
Tim, McTimothy, 321, 'bar', 5124.11
Bob, Bobbertson, 55, 'foo', 432.123
Claire, Rando, 191, 'tv', 700.00
Jimbo, Manman, 631, 'ps4', 450.00
What I've tried:
This query fails since it would require an aggregation on product_name and purchase_amount, but we don't want an aggregation, just the latest value.
SELECT first_name, last_name, customer_id, product_id
FROM purchases
GROUP BY first_name, last_name, customer_id
ORDER BY timestamp DESC
LIMIT 10
I think this will do it:
SELECT p.*
FROM
(
SELECT customer_id, MAX(timestamp) last_purchase_time
FROM purchases
GROUP BY customer_id
ORDER BY MAX(timestamp) DESC
LIMIT 5
) lp
INNER JOIN purchases p ON p.customer_id = lp.customer_id and p.timestamp = lp.last_purchase_time
The nested query gets the last purchase time for each customer, and further limits the nested result set to the 5 most recent customers. We then connect this back to the purchases table so we can see the full purchase data for the last purchase by each of those customers. This does make the assumption that a customer could not have two purchases at the exact same instance, but that's probably safe.
You could try adding a rank column that would act as an id, something like this:
SELECT first_name, last_name, customer_id, product_name
FROM
(SELECT first_name, last_name, customer_id, product_name, #rank := #rank + 1 AS rank
FROM purchases p1, (SELECT #rank := 0) r
ORDER BY timestamp DESC) p2
GROUP BY first_name, last_name, customer_id
LIMIT 10;
i'm assuming customer_id is unique. so we only need to use customer_id in
group clause
select * from purchases p2 where
concat(UNIX_TIMESTAMP((p2.timestamp)),'_',p2.customer_id)
in (
select concat(UNIX_TIMESTAMP(max(p.timestamp)),'_',p.customer_id)
from purchases p group by p.customer_id order by p.timestamp desc
) limit 10

group by, order by, distinct together

I have table with three columns (Trader, Product, Price). I want to get each Trader once and Product with max price to that Trader. When I select following I see repeated Traders:
select Trader, Product, Max(Price) as Price
from dbo.Sell
group by Trader, Product
order by Max(Price) desc
How can distinct Trader for the query above? The query below doesn't change anything:
select distinct Trader, Product, Max(Price) as Price
from dbo.Sell
group by Trader, Product
order by Max(Price) desc
Actually the following query does almost I want, however I want to see Product instead of Price.
select Trader, Max(Price) as Price
from dbo.Sell
group by Trader
Try this query, you would get multiple records only if a trader has more than one product with max price.
;with cte as (
select Trader, Max(Price) as Price
from dbo.Sell
group by Trader
)
select cte.Trader, s.Product, cte.Price
from cte join dbo.Sell s
on cte.Trader = s.Trader and cte.Price = s.Price
order by cte.Price desc
Second method would be to use a rank() function, but again rank() function will bring multiple records for same price records.
To get a single record, you can use Row_Number() in place of Rank().
;with cte as (
select Trader, Product, Price,
Rank() over (partition by Trader order by Price desc) rnk
from dbo.Sell
)
Select Trader, Product, Price
From cte
Where rnk = 1
Order by Price desc