I am trying to write a mysql query for an app I'm developing for android.
I have a database that has a bill_content table and a products table
I want to select top 10 most sold products.
This is a minimal version of what I have, but it's all I need to get an answer here.
bill_content table has the columns: id, id_product, quantity (id_product and quantity here can be duplicate because this table is larger, containing id_bill and other information)
products table has the columns: id, name
SELECT products.name AS Product,
bill_content.quantity AS Quantity
FROM bill_content, products
WHERE bill_content.id = products.id
ORDER BY bill_content.quantity DESC
LIMIT 10
Of course this returns a table of 2 rows containing all the products and their quantity in the bill_content table, but there are duplicates and I need to make sum of their quantity and display them as a single row.
Thank you in advance.
ANSWERED
This could be done using GROUP BY as Gordon Linoff said.
You want a group by. You should also learn to use proper explicit join syntax:
SELECT p.name AS Product,
SUM(bc.quantity) AS Quantity
FROM bill_content bc JOIN
products p
ON bc.id = p.id
GROUP BY p.name
ORDER BY SUM(bc.quantity) DESC
LIMIT 10;
Related
I want to write a SQL query in laravel/php, to fetch top 10 distinct products purchased by customer.
My table structure looks like this:
Orders table (customer id, product id, etc....)
Products table (product id, product name, etc....)
This is my query attempt:
SELECT products.*
FROM products
WHERE products.id = [SELECT DISTINCT (products.id)
FROM orders
WHERE customer.id=id->list(10)]
I can see where you're going with your attempted query but unfortunately that won't give you top 10. Instead, you might not get any result at all:
SELECT products.*
FROM products
WHERE products.id=[SELECT DISTINCT (products.id)
^^^ FROM orders
WHERE customer.id=id->list(10)]
The = means that you're looking for an exact match and your subquery suppose to returns 10 rows of data, which if you go with this operation, you'll receive this error.
Subquery returns more than 1 row
But if you change that to IN, you might receive this error instead
This version of MySQL doesn't yet support 'LIMIT & IN/ALL/ANY/SOME subquery'
With your current attempt, your option is to do a JOIN. However, I'm wondering how do you get your top 10? I can see that you're looking for top 10 of products but base on what? Sales amount? Quantity ordered?
On that note, here's an example of top 10 products by quantity ordered.
SELECT P.*
FROM Products P
JOIN ( SELECT product_id
FROM Orders
GROUP BY product_id
ORDER BY SUM(Qty) DESC
LIMIT 10) O
ON P.id=O.product_id;
The subquery is not necessary but I'm imitating what you tried with a subquery albeit not exactly the same process. Here it is without subquery:
SELECT P.*
FROM Orders O
JOIN Products P ON O.product_id=P.id
GROUP BY product_id
ORDER BY SUM(Qty) DESC
LIMIT 10;
Or perhaps you're looking for top 10 by sales amount?
SELECT P.*
FROM Orders O
JOIN Products P ON O.product_id=P.id
GROUP BY product_id
ORDER BY SUM(UnitPrice*Qty) DESC
LIMIT 10;
Demo fiddle
This is my homework task:
Products which were ordered along with the 5 most ordered products more than once and the count of orders they were included in. (Do not include the 5 most ordered products in the final result)
Products and orders are in same table. Order detail contain Order detail ID, order id, product id, quantity.
I've tried everything but I'm struggling with "along with" statement in the query.
Here is a query I have tried:
select
productid,
count
(
(select productid from orderdetails)
and
(select productid from orderdetails order by quantity desc limit 5)
) as ORDERS
from orderdetails
group by productid
order by ORDERS desc
You select from orderdetails, aggregate to get one result row per product and you count. It is very common to count rows with COUNT(*), but you can also count expressions, e.g. COUNT(mycolumn) where you just count those that are not null. You are counting an expresssion (because it is not COUNT(*) but COUNT(something else) that you are using). The expression to test for null and count is
(select productid from orderdetails)
and
(select productid from orderdetails order by quantity desc limit 5)
This, however is not an expression that leads to one value that gets counted (when it's not null) or not (when it's null). You are selecting all product IDs from the orderdetails table and you are selecting all the five product IDs from the orderdetails table that got ordered with the highest quantity. And then you apply AND as if these were two booleans, but they are not, they are data sets. Apart from the inappropriate use of AND which is an operator on booleans and not on data sets, you are missing the point here that you should be looking for products in the same order, i.e. compare the order number somehow.
So all in all: This is completely wrong. Sorry to say that. However, the task is not at all easy in my opinion and in order to solve it, you should go slowly, step by step, to build your query.
Products which were ordered along with the 5 most ordered products more than once
Dammit; such a short sentence, but that is deceiving ;-) There is a lot to do for us...
First we must find the 5 products that got ordered most. That means sum up all sales and find the five top ones:
select productid
from orderdetails
group by productid
order by sum(quantity) desc
limit 5
(The problem with this: What if six products got ordered most, e.g. products A, B, and C with a quantity of 200 and products D, E, and F with a quantity of 100? We would get the top three plus two of the top 4 to 6. In standard SQL we would solve this with a ties clause, but MySQL's LIMIT doesn't feature this.)
Anyway. Now we are looking for products that got ordered with these five products along. Does this mean with all five at once? Probably not. We are rather looking for products that were in the same order with at least one of the top five.
with top_5_products as
(query above)
, orders_with_top_5 as
(select orderid
from orderdetails
where productid in (select productid from top_5_products)
)
, other_products_in_order as
(select productid, orderid
from orderdetails
where orderid in (select orderid from orders_with_top_5)
and productid not in (select productid from top_5_products)
And once we've got there, we must even find products that got ordered with some of the top 5 "more than once" which I interpret as to appear in at least two orders containing top 5 products.
with <all the above>
select productid
from other_products_in_order
group by productid
having count(*) > 1;
And while we have counted how many orders the products share with top 5 products, we are still not there, because we are supposed to show the number of orders the products were included in, which I suppose refers to all orders, not only those containing top 5 products. That is another count, that we can get in the select clause for instance. The query then becomes:
with <all the above>
select
productid,
(select count(*) from orderdetails od where od.productid = opio.productid)
from other_products_in_order opio
group by productid
having count(*) > 1;
That's quite a lot for homework seeing that you are struggling with the syntax still. And we haven't even addressed that top-5-or-more ties problem yet (for which analytic functions come in handy).
The WITH clause is available since MySQL 8 and helps getting such a query that builds up step by step readable. Old MySQL versions don't support this. If working with an old version I suggest you upgrade :-) Else you can use subqueries directly instead.
I'm trying to merge these two statements into one query to get the a list of product names(or ids) against the average of their TTFF data, and I'm stuck.
select AVG(TTFF) from TTFFdata group by product_id
select product.product_name, count(*) from product join TTFFdata on product.product_id = TTFFdata.product_id
I've looked into using a temporary table (CREATE TEMPORARY TABLE IF NOT EXISTS averages AS (select AVG(TTFF) from TTFFdata group by product_id)) but couldn't get that to work with a join.
Anyone able to help me please?
You need to understand the components. Your second query is missing a group by. This would seem to be what you want:
select p.product_name, count(t.product_id), avg(t.TTFF)
from product p left join
TTFFdata t
on p.product_id = t.product_id
group by p.product_name
It is better to do group by on product_id, product_name for two reasons. One is, you can select product id along with product name. Second reason is, If the product name is not unique then it may give wrong results(this may be a rare scenario like product name is same but it differs based on other columns like version or model). The below is the final query.
select Product.product_id,
product_name,
AVG(TTFF) as Avg_TTFF
from Product
inner join
TTFFdata
on Product.product_id = TTFFdata.product_id
group by Product.product_id,Product.product_name
TTFFdata:
product:
Output:
let me sketch the situation a bit:
i have 2 tables: producten and reviews,
in producten i have multiple products stored, and in reviews i have stored all the reviews now while attemption to get the average of the ratings in the reviews table mysql only returns 1 row while i expect 2 rows back since i have 2 products.
the query im trying to use is:
SELECT p.*, CAST(AVG(r.rating) AS DECIMAL(2,1)) as waardering FROM `producten` as p INNER JOIN `reviews` as r ON p.id=r.product_id
i have also tried:
SELECT p.*, CAST(AVG(r.rating) AS DECIMAL(2,1)) as waardering FROM `producten` as p INNER JOIN `reviews` as r ON r.product_id=p.id
but this diddnt returned more then 1 row either.
could anyone please tell me why the query is only returning 1 row and not all the rows it finds inside the producten table?
also please feel free to tell me how i could increase this question if needed.
You want to GROUP BY p.id at the end of your query so that you get the average per product, instead of the values in the "first" product's field with the average for all products.
It's because you are using AVG. It is going to group all the rows together as one row. You probably want to group by avg rating instead.
So if I had a table with two columns.. product name / rating... I would do like so:
select productname, avg(rating) from ratings group by productname
I have 3 tables:
Orders
- id
- customer_id
Details
- id
- order_id
- product_id
- ordered_qty
Parcels
- id
- detail_id
- batch_code
- picked_qty
Orders have multiple Details rows, a detail row per product.
A detail row has multiple parcels, as 10'000 ordered qty may come from 6 different batches, so goods from batches are packed and shipped separately. The picked quantity put in each parcel for a detail row should then be the same as the ordered_qty.
... hope that makes sense.
Im struggling to write a query to provide summary information of all of this.
I need to Group By customer_id to provide a row of data per customer.
That row should contain
Their total number of orders
Their total ordered_qty of goods across all orders
Their total picked_qty of goods across all orders
I can get the first one with:
SELECT customer_id, COUNT(*) as number_of_orders
FROM Orders
GROUP BY Orders.customer_id
But when I LEFT JOIN the other two tables and add the
SELECT ..... SUM(Details.ordered_qty) AS total_qty_ordered,
SUM(Parcels.picked_qty) AS total_qty_picked
.. then I get results that dont seem to add up for the quantities, and the COUNT(*) seems to include the additional lines from the JOIN which obviously then isn't giving me the number of Orders anymore.
Not sure what to try next.
===== EDIT =======
Here's the query I tried:
SELECT
customer_id,
COUNT(*) as number_of_orders,
SUM(Details.ordered_qty) AS total_qty_ordered,
SUM(Parcels.picked_qty) AS total_qty_picked
FROM Orders
LEFT JOIN Details ON Details.order_id=Order.id
LEFT JOIN Parcels ON Parcels.detail_id=Detail.id
GROUP BY Orders.customer_id
try COUNT(distinct Orders.order_id) as number_of_orders,
as in
SELECT
customer_id,
COUNT(distinct Orders.order_id) as number_of_orders,
SUM(Details.ordered_qty) AS total_qty_ordered,
(select SUM(Parcels.picked_qty)
FROM Parcels WHERE Parcels.detail_id=Detail.id ) AS total_qty_picked
FROM Orders
LEFT JOIN Details ON Details.order_id=Order.id
GROUP BY Orders.customer_id
EDIT: added an other select with subselect
Is there any particular reason you feel the need to combine all these in one query? Simplify by breaking it up in to separate queries, and if you want a single call to get the results, put the queries in a stored procedure, using temp tables.