Magento: How to query (SQL) top selling products? - sql

Im seeking for a SQL query to directly get a list of our top selling products (ordered by quantity or by amount - doesn´t really matter). This seems to be more difficult than I thought...
Searching with google only finds solutions for PHP-modules and so on - but I want SQL.
I have picked up a small query from a different site and modified it a bit:
SELECT
SUM(order_items.qty_ordered) AS ordered_qty, order_items.name AS order_items_name, order_items.product_id AS entity_id,
e.entity_type_id, e.attribute_set_id, e.type_id, e.sku, e.has_options, e.required_options, e.created_at,
e.updated_at FROM sales_flat_order_item AS order_items
INNER JOIN sales_flat_order AS `order` ON `order`.entity_id = order_items.order_id AND `order`.state <> 'canceled'
LEFT JOIN catalog_product_entity AS e
ON
-- (e.type_id NOT IN ('grouped', 'configurable', 'bundle'))
-- AND
e.entity_id = order_items.product_id AND e.entity_type_id = 4
--AND state = "complete"
WHERE (parent_item_id IS NULL)
GROUP BY order_items.product_id
HAVING (SUM(order_items.qty_ordered) > 0)
ORDER BY ORDERED_QTY DESC
It more or less seems to give a reasonable output - but the numbers differ from the admin-start screen (where only the top 5 are displayed).
Has anybody done smth. similar to that already?

Have a solution (query) now
select
year_ordered,
product_type,
sku,
name,
sum(qty_ordered) as qty,
sum(row_total) as total
from (
SELECT
YEAR(so.created_at) AS year_ordered,
-- order_id,
product_type, sku, name, qty_ordered, price, row_total
FROM `sales_flat_order` AS so
INNER JOIN `sales_flat_order_item` AS si ON si.order_id=so.entity_id
AND (so.state != "canceled" )
ORDER BY so.created_at desc
) stat
group by stat.year_ordered, stat.product_type, stat.sku, stat.name
order by year_ordered desc, total desc
I´m using a subquery to be able to control that counting the products is correct.
SELECT
YEAR(so.created_at) AS year_ordered,
-- order_id,
product_type, sku, name, qty_ordered, price, row_total
FROM `sales_flat_order` AS so
INNER JOIN `sales_flat_order_item` AS si ON si.order_id=so.entity_id
AND (so.state != "canceled" )
ORDER BY so.created_at desc
Result is a list of the ordered products per year. If you want to see a best seller list over all years a slight modification is sufficient (here ordered by total).
select
product_type,
sku,
name,
sum(qty_ordered) as qty,
sum(row_total) as total
from (
SELECT
YEAR(so.created_at) AS year_ordered,
-- order_id,
product_type, sku, name, qty_ordered, price, row_total
FROM `sales_flat_order` AS so
INNER JOIN `sales_flat_order_item` AS si ON si.order_id=so.entity_id
AND (so.state != "canceled" )
ORDER BY so.created_at desc
) stat
group by stat.product_type, stat.sku, stat.name
order by total desc

Related

Include the sales revenue amount into the select query

I also have a (somewhat) similar scenario as from this guy.
This is my current code:
SELECT Vendor_Name, Product
FROM (
SELECT v.Vendor_Name, p.Description AS Product, ROW_NUMBER() OVER (PARTITION BY v.Vendor_Key ORDER BY SUM(sf.Price * sf.Quantity) DESC) AS seqnum
FROM SalesFacts sf JOIN Vendor v
ON sf.Vendor_Key = v.Vendor_Key JOIN Product p
ON sf.Product_Key = p.Product_Key
GROUP BY v.Vendor_Key, v.Vendor_Name, p.Product_Key, p.Description
) vp
WHERE vp.seqnum = 1
The result of the query is show as below:
What the above query did was to extract the top-grossing product for each vendor from the entire database, or in other words, the query obtained the highest-revenue product per vendor.
I wanted to add in a new column, which is Sales Revenue, which calculation can be derived as such:
price of item * quantity. I wanted to add in the new column so that i can see see how much revenue the vendor earned from their respective best-selling products.
How do i obtain the same result with the inclusion of sales revenue column?
The way your question is asked, you just want to return this column from the subquery so it can be accessed in the outer query:
SELECT Vendor_Name, Product, Sales_Revenue
FROM (
SELECT
v.Vendor_Name,
p.Description AS Product,
SUM(sf.Price * sf.Quantity) Sales_Revenue
ROW_NUMBER() OVER (PARTITION BY v.Vendor_Key ORDER BY SUM(sf.Price * sf.Quantity) DESC) AS seqnum
FROM SalesFacts sf JOIN Vendor v
ON sf.Vendor_Key = v.Vendor_Key JOIN Product p
ON sf.Product_Key = p.Product_Key
GROUP BY v.Vendor_Key, v.Vendor_Name, p.Product_Key, p.Description
) vp
WHERE vp.seqnum = 1

Oracle - Outer Join with join condition

I have a scenario where I have two tables
ORDER
ORDER_NO
LOCATION
ITEM
QTY_RECEIVED
SHIPMENT
ORDER_NO
LOCATION
ITEM
QTY_RECEIVED
There are cases where ORDER table has a record but SHIPMENT table doesn't
I want all the rows from ORDER table where the qty is not equal to the qty in SHIPMENT table, and that will include the rows which are there in ORDER but not in shipment.
I tried doing by this:
SELECT
order_no, item, location, SUM(NVL(QTY_RECEIVED, 0))
FROM
ORDERS ol
GROUP BY
ORDER_NO, ITEM, LOCATION
HAVING
SUM (NVL(ol.QTY_RECEIVED,0)) <>
(SELECT SUM(NVL(sk.QTY_RECEIVED, 0))
FROM shipment s
WHERE s.order_no = ol.order_no
AND s.item (+)= ol.item
AND s.location (+) = ol.location
GROUP BY s.order_no, s.item, s.location);
But it doesn't give the correct result.
how should I do this?
You need LEFT JOIN in order to return the the results even for the non-existing values of SHIPMENT table :
SELECT ol.order_no, ol.item, ol.location,
SUM(NVL(ol.QTY_RECEIVED, 0)) AS "Total Quantity Of Orders",
SUM (NVL(s.QTY_RECEIVED,0)) AS "Total Quantity Of Shpm."
FROM orders ol
LEFT JOIN shipment s
ON s.order_no = ol.order_no
AND s.item = ol.item
AND s.location = ol.location
GROUP BY ol.order_no, ol.item, ol.location
HAVING SUM (NVL(ol.QTY_RECEIVED,0)) <> SUM (NVL(s.QTY_RECEIVED,0))
It seems possible to me that an order could have multiple shipments for the same item. If this is the case, you need a different approach:
select order_no, location, item, sum(o_qty), sum(s_qty)
from ((select order_no, location, item, qty_received as o_qty, 0 as s_qty
from orders
) union all
(select order_no, location, item, 0 as o_qty, qty_received as s_qty
from shipment
)
) os
group by order_no, location, item
having sum(o_qty) <> sum(s_qty);

Select data based on latest transaction date for each item

I have a query which I want it to list all latest transaction's price for each stock item. I've tried to use MAX() to list all latest transaction for each item without including the price and it works but when I included the price, the method will not work.
Here's my query
SELECT MAX(DocDate) AS DocDate, StockCode, Price
FROM StockPurchasePriceHistory spph
INNER JOIN Stocks s
ON spph.Stock = s.Id
GROUP BY StockCode, Price
ORDER BY StockCode ASC
Output
use row_number
select * from (SELECT row_number()over(partition by StockCode order by DocDate desc) rn
, StockCode, Price
FROM StockPurchasePriceHistory spph
INNER JOIN Stocks s
ON spph.Stock = s.Id
) a where a.rn=1
try this:
SELECT MAX(DocDate) AS DocDate, StockCode, sum(Price) as Price
FROM StockPurchasePriceHistory spph
INNER JOIN Stocks s
ON spph.Stock = s.Id
GROUP BY StockCode
ORDER BY StockCode ASC
This is a good place to use APPLY:
SELECT spph.DocDate, s.StockCode, spph.Price
FROM Stocks s CROSS APPLY
(SELECT TOP (1) spph.*
FROM StockPurchasePriceHistory spph
WHERE spph.Stock = s.Id
ORDER BY spph.DocDate DESC
) spph;
With an index on StockPurchasePriceHistory(Stock, DocDate desc), I would expect this to be a bit faster than alternatives using window functions and approximately as fast as a correlated subquery.

Display Product Name and City where that product sold in largest quantity

I'm trying to get a query to display the product name and city where the product had the highest quantity sold. Here is the code I'm working with:
SELECT DISTINCT
(s.city),
MAX(t.quantity),
p.Name
FROM [DS715-Cameron-Erwin].dbo.Tb_Transactions AS t,
[DS715-Cameron-Erwin].dbo.Tb_Product AS p,
[DS715-Cameron-Erwin].dbo.Tb_Supplier AS s
WHERE p.prod_id = t.prod_id
AND s.Supp_ID = t.Supp_ID
GROUP BY t.Prod_ID,
p.name,
s.city
ORDER BY p.name, s.city
This is giving me the highest quantity sold for each product in each city.
Sample Data
From the screenshot there are multiple records for each product (Airplane, Auto, Boat...). I'm trying to get a single record for each product where ever the highest quantity was purchased.
So, the top record would only show for Airplane because the most orders were from there.
You want to use the ROW_NUMBER() OVER functionality to order by the quantity and then select the one with the biggest quantity over each product.
SELECT
city,
quantity,
name
FROM
(
SELECT S.city,
T.quantity,
P.name,
ROW_NUMBER() OVER
( PARTITION BY
P.name
ORDER BY t.Quantity DESC
) as RowNum
FROM
Tb_Transactions T
INNER JOIN
Tb_Product P
ON
P.prod_id = T.prod_id
INNER JOIN
Tb_Supplier S
ON
S.supp_id = T.supp_id
) a
WHERE
RowNum = 1
http://sqlfiddle.com/#!6/628458/5
For this, I would use a CTE (also I would use the explicit INNER JOIN syntax):
;With CTE
As
(
Select
s.city
, t.quantity
, p.Name
, Row_Number Over (Partition By P.Name, s.city Order By t.Quantity Desc) as RN
From [DS715-Cameron-Erwin].dbo.Tb_Transactions as t
Inner Join [DS715-Cameron-Erwin].dbo.Tb_Product as p
On p.prod_id = t.prod_id
Inner Join [DS715-Cameron-Erwin].dbo.Tb_Supplier as s
On s.Supp_ID = t.Supp_ID
)
Select
city
, quantity
, Name
From CTE
Where RN = 1

SQL nested aggregate grouping error

I'm trying to find name of product which has sold maximum units, I've two tables, purchases and products, products has pname and pid, purchases has pid, qty(units sold).
I've managed this
select p.pname, sum(q.qty) from purchases q
inner join products p on p.pid=q.pid
where p.pid=q.pid
group by p.pname
order by sum(q.qty) desc
I'm getting the result in descending order but I need only the top most selling units, multiple products can have top most selling units. When I use
max(sum(q.qty))
I get grouping error.
One approach is to derive the values first using a common table expression.
Simply put you can't wrap aggregates in other aggregates. You may be able to wrap an aggregate around an analytic however.
with cte as (select p.pname, sum(q.qty) from purchases q
inner join products p on p.pid=q.pid
where p.pid=q.pid
group by p.pname
order by sum(q.qty) desc)
Select pname, max(purchases)
from cte
group by pname
You can use ctes to do this.
1)First get the total quantity of each product
2)Then get the maximum of all those totals
3)Join it with your original query
with totals as (select pid, sum(qty) totalqty from purchases group by pid)
, t1 as (select p.pid, p.pname, sum(q.qty) totqty
from purchases q
inner join products p on p.pid=q.pid
group by p.pname)
, t2 as (select max(totalqty) maxtotal from totals)
select pname, totqty
from t1
join t2 on t1.totqty = t2.maxtotal
Analytics can simplify this for you. If you have more than one product with the same sum(qty) and that happens to be the max(sum(qty)), then this should get you them:
select pname, quantity
FROM (
select p.pname
, sum(q.qty) quantity
,rank() over (order by sum(q.qty desc) ranking
from purchases q
inner join products p on p.pid=q.pid
group by p.pname
)
where ranking = 1