SQL for highest sold Products - sql

Order Sample data:
ORDER_DAY ORDER_ID PRODUCT_ID QUANTITY PRICE
---------- --------- ----------- ---------- ---------
01-JUL-11 O1 P1 5 5
01-JUL-11 O2 P2 2 10
01-JUL-11 O3 P3 10 25
01-JUL-11 O4 P1 20 5
02-JUL-11 O5 P3 5 25
02-JUL-11 O6 P4 6 20
02-JUL-11 O7 P1 2 5
02-JUL-11 O8 P5 1 50
02-JUL-11 O9 P6 2 50
02-JUL-11 O10 P2 4 10
Q: Get me highest sold Products (Qty* Price) on both days
Desired output :
DATE PRODUCT_ID SOLD_AMOUNT
01-JUL-11 P3 250
02-JUL-11 P3 125

Try following query:
select order_day, product_id, totalsale
from (select order_day,
product_id,
nvl(QUANTITY, 0) * PRICE as totalsale,
dense_rank() over(partition by ORDER_DAY order by(nvl(QUANTITY, 0) * PRICE) desc) as maxsum
from orders )
where maxsum = 1;

You would start with getting the sold amount per day and product. With this data you first select the maximum profit per day and then select those entries that match this:
WITH PRODUCT_PER_DAY AS
(
SELECT ORDER_DAY, PRODUCT_ID, SUM(QUANTITY * PRICE) AS SOLD_AMOUNT
FROM MYTABLE
GROUP BY ORDER_DAY, PRODUCT_ID
)
SELECT ORDER_DAY, PRODUCT_ID, SOLD_AMOUNT
FROM PRODUCT_PER_DAY
WHERE (ORDER_DAY, SOLD_AMOUNT) IN
(
SELECT ORDER_DAY, MAX(SOLD_AMOUNT)
FROM PRODUCT_PER_DAY
GROUP BY ORDER_DAY
)
ORDER BY ORDER_DAY, PRODUCT_ID;

select b.product_id,a.order_day,a.total_price from(select order_day, max(quantity*price)as total_price from order group by order_day)a
join (select product_id , quantity * price as total_amount from order)b on
a.total_price= b.total_price

Try this out (modify the table and column names as per your needs):
Select a.order_day, b.product_id, a.sales
from
(select order_day, max(quantity*price) as sales
from ordr
group by order_day) a
inner join
(select order_day, product_id, quantity*price as sales
from ordr) b
on a.order_day = b.order_day and a.sales = b.sales;

with temp as
(select order_day,product_id,sum(quantity*price) qp
from orders_amazn
group by order_day,product_id
)
select * from (select order_day,product_id,qp,
dense_rank() over (partition by order_day order by qp desc) rnk
from temp)
where rnk=1;

select date,product_id,max(product_id*price) as sold_amount form order
group by order_day
order by order_day

select t.ORDER_DAY as date1 ,t.PRODUCT_ID,max(t.quantity * t.price)
as sold_amount from table t group by t.ORDER_DAY,t.PRODUCT_ID

Kindly use this query you will be the desired output.I have tried in MySQL.
SELECT
order_date,
Product_id,
sold_amount
FROM
(
SELECT
date_format(order_day,'%d-%b-%y') AS order_date,
Product_id,
SUM(price*quantity) AS sold_amount
FROM
ecommerce
GROUP BY
date_format(order_day,'%d-%b-%y'),
product_id) a
WHERE
(
order_date,sold_amount) IN
(
SELECT
DATE,
MAX(sold_amt) AS sold_amount
FROM
(
SELECT
date_format(order_day,'%d-%b-%y') AS DATE,
product_id,
SUM(price*quantity) AS sold_amt
FROM
ecommerce
GROUP BY
date_format(order_day,'%d-%b-%y'),
product_id)a
GROUP BY
DATE)

select order_day as orderdate,product_id,max(quantity * price) as sold_amount
from order
group by order_day
order by product_id

Related

How to get the most sold Product in PostgreSQL?

Given a table products
pid
name
123
Milk
456
Tea
789
Cake
...
...
and a table sales
stamp
pid
units
14:54
123
3
15:02
123
9
15:09
456
1
15:14
456
1
15:39
456
2
15:48
789
12
...
...
...
How would I be able to get the product(s) with the most sold units?
My goal is to run a SELECT statement that results in, for this example,
pid
name
123
Milk
789
Cake
because the sum of sold units of both those products is 12, the maximum value (greater than 4 for Tea, despite there being more sales for Tea).
I have the following query:
SELECT DISTINCT products.pid, products.name
FROM sales
INNER JOIN products ON sale.pid = products.pid
INNER JOIN (
SELECT pid, SUM(units) as sum_units
FROM sales
GROUP BY pid
) AS total_units ON total_units.pid = sales.pid
WHERE total_units.sum_units IN (
SELECT MAX(sum_units) as max_units
FROM (
SELECT pid, SUM(units) as sum_units
FROM sales
GROUP BY pid
) AS total_units
);
However, this seems very long, confusing, and inefficient, even repeating the sub-query to obtain total_units, so I was wondering if there was a better way to accomplish this.
How can I simplify this? Note that I can't use ORDER BY SUM(units) LIMIT 1 in case there are multiple (i.e., >1) products with the most units sold.
Thank you in advance.
Since Postgres 13 it has supported with ties so your query can be simply this:
select p.pId, p.name
from sales s
join products p on p.pid = s.pid
group by p.pId, p.name
order by Sum(units) desc
fetch first 1 rows with ties;
See demo Fiddle
Solution for your problem:
WITH cte1 AS
(
SELECT s.pid, p.name,
SUM(units) as total_units
FROM sales s
INNER JOIN products p
ON s.pid = p.pid
GROUP BY s.pid, p.name
),
cte2 AS
(
SELECT *,
DENSE_RANK() OVER(ORDER BY total_units DESC) as rn
FROM cte1
)
SELECT pid,name
FROM cte2
WHERE rn = 1
ORDER BY pid;
Working example: db_fiddle link

How to show the count of all items in cross joined table in SQL Server

I have a table that has all Items in the inventory, table called CI
CI has 2 columns (ProdID and Price), and it looks like this
ProdID Price
-------------
A8373 700
G8745 900
J7363 300
K7222 800
Y6311 350
I have another table for documents called Docs with columns DocID, CustID and InvoiceID.
DocID, CustID, InvoiceID
------------------------
1 1001 751
2 1001 752
3 1001 753
4 1002 831
5 1002 832
6 1003 901
7 1003 902
Another table for purchases called Purchase with DocID, ProdID, ProdSize.
In the same invoice, ProdID can be repeated as it can be in different sizes
DocID, ProdID, ProdSize
------------------------
1 A8373 41
1 A8373 42
1 A8373 43
1 G8745 35
1 G8745 36
2 A8373 44
2 A8373 45
Now I want to get the quantity of of products for all customer and invoice, but for highest priced products
So it should be like this
CustID, InvoiceID, ProdID, Quantity
-----------------------------------
1001 751 A8373 3
1001 751 G8745 2
1001 751 K7222 0
1001 752 A8373 2
1001 752 G8745 0
1001 752 K7222 0
and to show 0 for the products that do not exist in that invoice
I wrote this query, but it is extremely slow. I wonder if there is an easier fast way to get this results
DECLARE #Features AS TABLE
(
CustID varchar(100),
InvoiceID varchar(100)
INDEX IX3 CLUSTERED(CustID, InvoiceID),
ProdID varchar(100),
Quantity bigint
)
INSERT INTO #Features (CustID, InvoiceID, ProdID, Quantity)
SELECT
R.CustID, R.InvoiceID, T.ProdID, COUNT(*) AS Quantity
FROM
Docs R
CROSS JOIN
(SELECT TOP 1000 * FROM CIs ORDER BY Price DESC) C
INNER JOIN
Purchase T ON T.DocID = R.DocID
GROUP BY
R.CustID, R.InvoiceID, T.ProdID
SELECT TOP 100 *
FROM #Features
ORDER BY CustID, InvoiceID, ProdID
SELECT COUNT(*) FROM #Features
UPDATE F
SET Quantity = Cnt
FROM #Features F
INNER JOIN
(SELECT R.CustID, R.InvoiceID, COUNT(*) Cnt
FROM Purchase T
INNER JOIN Docs R ON T.DocID = R.DocID
GROUP BY R.CustID, R.InvoiceID ) X ON F.CustID = X.CustID
AND F.InvoiceID = X.InvoiceID
SELECT * FROM #Features
here is a way to do this. I filter out the 1000 products first and then perform the join as follows..
Also there isn't a need for update query, all could be obtained in the SQL itself.
Filter early join late
with top_product
as (select prodid,price, rownumber() over(order by price desc) as rnk
from ci
)
,invoice_product
as(select d.docid,d.custid,d.invoiceid,p.prodid
from top_product
join docs d
on 1=1
and rnk<=1000
)
select a.CustID, a.InvoiceID, a.ProdID,count(b.prodid) as qty
from invoice_product a
left join purchase b
on a.DocID=b.docid
and a.ProdID=b.prodid
group by a.CustID, a.InvoiceID, a.ProdID
You can use the DENSE_RANK as follows:
select CustID, InvoiceID, ProdID, sum(qty) as qty
from (select d.CustID, d.InvoiceID, ci.ProdID, p.prodid as qty,
dense_rank() over (order by ci.price desc) as rn
from ci cross join docs d
left join purchase p on d.docid = p.docid and ci.prodid = p.prodid) t
where rn <= 1000
group by CustID, InvoiceID, ProdID
Can you please try following SQL Select statement where I used Common Table Expression SQL CTEs
with topproducts as (
select top 3 ProdID from CI order by Price desc
), sales as (
select
CustID,
InvoiceID,
ProdId,
count(ProdId) as cnt
from (
select
d.CustID,
d.InvoiceID,
p.ProdId
from Docs d
inner join Purchase p
on p.DocID = d.DocID
where p.ProdId in (select ProdId from topproducts)
) t1
group by
CustID,
InvoiceID,
ProdId
)
select
t.*, isnull(ss.cnt,0) as Qty
from (
select
distinct s.CustID, s.InvoiceID, p.ProdId
from sales s, topproducts p
) t
left join sales ss on ss.InvoiceID = t.InvoiceID and ss.ProdId = t.ProdId

Using two aggregate function - min and max on same query

Here is my product table's data -
product_id category discount
454 C-10 10
357 C-10 9
64 C-10 10
294 C-11 17
449 C-11 17
471 C-11 17
89 C-11 12
56 C-11 10
I want to get the max discount for every product category and if any category has multiple products having same discount, the product having the minimum
product_id should be selected.
Desired output -
product_id category discount
64 C-10 10
294 C-11 17
I tried below two query but not working -
select category,min(product_id),max(discount)
from Product
group by category
Your help is very much appreciated. Thanks!
Using ROW_NUMBER is helpful here:
WITH cte AS (
SELECT product_id, category, discount,
ROW_NUMBER() OVER (PARTITION BY category
ORDER BY discount DESC, product_id) rn
FROM Product
)
SELECT product_id, category, discount
FROM cte
WHERE rn = 1;
Or, we could even do this without using a subquery/CTE:
SELECT TOP 1 WITH TIES product_id, category, discount
FROM Product
ORDER BY
ROW_NUMBER() OVER (PARTITION BY category
ORDER BY discount DESC, product_id);
use row_number()
select * from
(
select *,row_number() over(partition by category order by discount desc, poroduct_id asc) rn
from tablename
)A where rn=1
OR
use correlated subquery
select * from tablename a where discount in
(select max(discount) from tablename b where a.category=b.category
having min(b.product_id)=a.product_id)
use outer apply
with cte as
(
select 454 as product_id, 'C-10' as category, 10 as discount union all
select 357,'C-10',9 union all
select 64,'C-10',10 union all
select 294,'C-11',17 union all
select 449,'C-11',17 union all
select 471,'C-11',17 union all
select 89,'C-11', 12 union all
select 56,'C-11', 10
) select distinct p1.category,a.product_id,a.discount
from cte p1
outer apply ( select top 1 p2.*
from cte p2 where p1.category=p2.category
order by discount desc, product_id asc
) a
output
category product_id discount
C-10 64 10
C-11 294 17
demo link

Oracle SQL - Get records with latest date on non-unique data

Following is the example of records in the table -
ITEM_NAME STORAGE_CODE STOCK DATE
ABC 2233 170 27/09/2017
ABC 2233 270 15/09/2017
DEF 2233 120 23/09/2017
DEF 2233 110 11/09/2017
GHI 2233 50 15/09/2017
Expected result:
ITEM_NAME STORAGE_CODE STOCK DATE
ABC 2233 170 27/09/2017
DEF 2233 120 23/09/2017
GHI 2233 50 15/09/2017
I've tried using the below query:
Select ITEM_NAME, STORAGE_CODE, STOCK, MAX(DATE)
FROM ITEM_TABLE
WHERE ITEM_NAME IN ('ABC','DEF','GHI' .........)
GROUP BY ITEM_NAME, STORAGE_CODE, STOCK
This didn't work as the stock value is not unique.
Please note: I'm using ITEM_NAME IN (), because I need the output for some specific items.
You can add a select top and order by to your query if you just want to get the max date, like this:
SELECT TOP 1
ITEM_NAME,
STORAGE_CODE,
STOCK,
MAX(DATE)
FROM ITEM_TABLE
WHERE ITEM_NAME IN('ABC', 'DEF', 'GHI')
GROUP BY ITEM_NAME,
STORAGE_CODE,
STOCK
ORDER BY DATE DESC
EDIT: Using row_num
SELECT T.ITEM_NAME,
T.STORAGE_CODE,
T.STOCK,
T.DATE
FROM
(
SELECT ITEM_NAME,
STORAGE_CODE,
STOCK,
DATE,
ROW_NUMBER() OVER(PARTITION BY ITEM_NAME,
STORAGE_CODE ORDER BY DATE DESC) AS part
FROM ITEM_TABLE
WHERE ITEM_NAME IN('ABC', 'DEF', 'GHI')
) T
WHERE part = 1;
I think a query like this should work:
select
*
from (
select *,
row_number() over (partition by ITEM_NAME, STORAGE_CODE order by DATE desc) as seq
from ITEM_TABLE
where ITEM_NAME in ('ABC','DEF','GHI' .........)
) t
where seq = 1
You can use Oracle row_number() over(partition by) like following
select ITEM_NAME
, STORAGE_CODE
, STOCK
, DATE
from
(
select ITEM_NAME
, STORAGE_CODE
, STOCK
, DATE
, row_number() over(partition by ITEM_NAME order by DATE desc) as rn
from ITEM_TABLE
) s
where rn = 1
One way could be to get the max value from DATE1 column in inner query and corresponding stock value in outer query using join as below.
SELECT t.*
,t1.STOCK
FROM (
SELECT ITEM_NAME
,STORAGE_CODE
,MAX(DATE1) AS DATE1
FROM table1
GROUP BY ITEM_NAME
,STORAGE_CODE
ORDER BY ITEM_NAME
) t
INNER JOIN table1 t1 ON t.ITEM_NAME = t1.ITEM_NAME
AND t.STORAGE_CODE = t1.STORAGE_CODE
AND t.DATE1 = t1.DATE1
Result:
ITEM_NAME STORAGE_CODE DATE1 STOCK
------------------------------------------------------
ABC 2233 27.09.2017 00:00:00 170
DEF 2233 23.09.2017 00:00:00 120
GHI 2233 15.09.2017 00:00:00 50
DEMO

SQL - Finding Customer's largest Location by Order $

I have a table with customer IDs, location IDs, and their order values. I need to select the location ID for each customer with the largest spend
Customer | Location | Order $
1 | 1A | 100
1 | 1A | 20
1 | 1B | 100
2 | 2A | 50
2 | 2B | 20
2 | 2B | 50
So I would get
Customer | Location | Order $
1 | 1A | 120
2 | 2B | 70
I tried something like this:
SELECT
a.CUST
,a.LOC
,c.BOOKINGS
FROM (SELECT DISTINCT TOP 1 b.CUST, b.LOC, sum(b.ORDER_VAL) as BOOKINGS
FROM ORDER_TABLE b
GROUP BY b.CUST, b.LOC
ORDER BY BOOKINGS DESC) as c
INNER JOIN ORDER_TABLE a
ON a.CUST = c.CUST
But that just returns the top order.
Just use variables to emulate ROW_NUM()
DEMO
SELECT *
FROM ( SELECT `Customer`, `Location`, SUM(`Order`) as `Order`,
#rn := IF(#customer = `Customer`,
#rn + 1,
IF(#customer := `Customer`, 1, 1)
) as rn
FROM Table1
CROSS JOIN (SELECT #rn := 0, #customer := '') as par
GROUP BY `Customer`, `Location`
ORDER BY `Customer`, SUM(`Order`) DESC
) t
WHERE t.rn = 1
Firs you have to sum the values for each location:
select Customer, Location, Sum(Order) as tot_order
from order_table
group by Customer, Location
then you can get the maximum order with MAX, and the top location with a combination of group_concat that will return all locations, ordered by total desc, and substring_index in order to get only the top one:
select
Customer,
substring_index(
group_concat(Location order by tot_order desc),
',', 1
) as location,
Max(tot_order) as max_order
from (
select Customer, Location, Sum(Order) as tot_order
from order_table
group by Customer, Location
) s
group by Customer
(if there's a tie, two locations with the same top order, this query will return just one)
This seems like an order by using aggregate function problem. Here is my stab at it;
SELECT
c.customer,
c.location,
SUM(`order`) as `order_total`,
(
SELECT
SUM(`order`) as `order_total`
FROM customer cm
WHERE cm.customer = c.customer
GROUP BY location
ORDER BY `order_total` DESC LIMIT 1
) as max_order_amount
FROM customer c
GROUP BY location
HAVING max_order_amount = order_total
Here is the SQL fiddle. http://sqlfiddle.com/#!9/2ac0d1/1
This is how I'd handle it (maybe not the best method?) - I wrote it using a CTE first, only to see that MySQL doesn't support CTEs, then switched to writing the same subquery twice:
SELECT B.Customer, C.Location, B.MaxOrderTotal
FROM
(
SELECT A.Customer, MAX(A.OrderTotal) AS MaxOrderTotal
FROM
(
SELECT Customer, Location, SUM(`Order`) AS OrderTotal
FROM Table1
GROUP BY Customer, Location
) AS A
GROUP BY A.Customer
) AS B INNER JOIN
(
SELECT Customer, Location, SUM(`Order`) AS OrderTotal
FROM Table1
GROUP BY Customer, Location
) AS C ON B.Customer = C.Customer AND B.MaxOrderTotal = C.OrderTotal;
Edit: used the table structure provided
This solution will provide multiple rows in the event of a tie.
SQL fiddle for this solution
How about:
select a.*
from (
select customer, location, SUM(val) as s
from orders
group by customer, location
) as a
left join
(
select customer, MAX(b.tot) as t
from (
select customer, location, SUM(val) as tot
from orders
group by customer, location
) as b
group by customer
) as c
on a.customer = c.customer where a.s = c.t;
with
Q_1 as
(
select customer,location, sum(order_$) as order_sum
from cust_order
group by customer,location
order by customer, order_sum desc
),
Q_2 as
(
select customer,max(order_sum) as order_max
from Q_1
group by customer
),
Q_3 as
(
select Q_1.customer,Q_1.location,Q_1.order_sum
from Q_1 inner join Q_2 on Q_1.customer = Q_2.customer and Q_1.order_sum = Q_2.order_max
)
select * from Q_3
Q_1 - selects normal aggregate, Q_2 - selects max(aggregate) out of Q_1 and Q_3 selects customer,location, sum(order) from Q_1 which matches with Q_2