Need a postgresql query to group and order - sql

I have a customers table as following:
customername, ordername, amount
=============================
bob, book, 20
bob, computer, 40
steve,hat, 15
bill, book, 12
bill, computer, 3
steve, pencil, 10
bill, pen, 2
I want to run a query to get the following result:
customername, ordername, amount
=============================
bob, computer, 40
bob, book, 20
bob, ~total~, 60
steve, hat, 15
steve, pencil, 10
steve, ~total~,25
bill, book, 12
bill, computer, 3
bill, pen, 2
bill, ~total~, 17
I want the amount for each customer to be ordered from max to min and a new ordername as "~total~" (must always be the last row for each customer) with a result as sum of all amount for the same customer.
So, in above example, bob should be the first since the total=60, steve the second (total=25) and bill the third (total=17).

Use:
SELECT x.customername,
x.ordername,
x.amount
FROM (SELECT a.customername,
a.ordername,
a.amount,
y.rk,
1 AS sort
FROM CUSTOMERS a
JOIN (SELECT c.customername,
ROW_NUMBER() OVER (ORDER BY SUM(c.amount) DESC) AS rk
FROM CUSTOMERS c
GROUP BY c.customername) y ON y.customername = a.customername
UNION ALL
SELECT b.customername,
'~total~',
SUM(b.amount),
ROW_NUMBER() OVER (ORDER BY SUM(b.amount) DESC) AS rk,
2 AS sort
FROM CUSTOMERS b
GROUP BY b.customername) x
ORDER BY x.rk, x.customername, x.sort, x.amount DESC
You could look at using GROUP BY ROLLUP, but the ordername value would be NULL so you'd have to post-process it to get that replaced with "~total~"...

Related

Get the maximum count for each repeating value in a table and link it to another value

Please help me figure out this:
Let us say we have a restaurant with 3 different menu items
A
B
C
and in another table, we have customer name, date of order, order number
Example:
Jack, A, May 22
Jack, A, May 23
Ryan, A, May 23
Emily, B May 24
Jack, A May 25
Emily, B, May 25
Ryan B, May 26
Hannah, C, May 28
Jack, C, May 28
Emily C, May 29
Hannah C, May 30
I want to know which customer have the highest count for each menu item, and what is that count
Example of output
Order .... Customer....Count
A Jack 3
B Emily 2
C Hannah 2
What is the proper sql query statement (oracle) to get such a result?
You can use aggregation and window functions:
select co.*
from (select customer, ord, count(*) as cnt,
row_number() over (partition by ord order by count(*) desc) as seqnum
from t
group by customer, ord
) co
where seqnum = 1;

COUNT OF in SQL Query?

I only want the count of Brands (Blue, White, Red) if their corresponding Customer value is listed more than once.
*customer* *productid* *brand*
1 A Red
2 B Blue
1 A Red
2 C Blue
3 B White
1 A Red
2 B Blue
Desired result: I want a single dataset that has the Brands with their tallied count, only for Customers that are repeat purchasers.
*brands* *repeat_purchase*
Red 3
Blue 2
select customer, productid, count(productid) as repeat_purchase
from Public."CustomerData"
group by customer, productid
having count(productid) > 1;
Above is what I have so far, but I can't figure out how to get just two columns: One with the name of each Brand, and one with the total number of times a that each brand is included in a repeat purchase.
Your question seems to want two levels of aggregation:
select brand, sum(cnt)
from (select customer, product, brand, count(*) as cnt
from Public."CustomerData"
group by customer, product, brand
having count(*) >= 2
) t
group by brand;

Find out the top 3 customers by sum of sales from different groups for the last 30 days - Amazon interview

This was my Amazon SQL interview question which I bombed miserably.
We have 3 tables:
customers orders catalog
cust_id order_date catalog_id
cust_name order_id catalog_name
unit_price cust_id
quantity
catalog_id
The output expected was to find top 3 customers from the 3 catalog / business units for the last 30 days. I tried partitioning over total sales but the last 30 day sales and multiple joins threw me off. Following were the columns requested:
cust_id cust_name catalog_name total_sales(unit_price*quantity)
1 David Books 1400
2 John Books 1200
3 Lisa Books 1000
4 Paul DVDs 500
2 John DVDs 313.5
5 James DVDs 220
6 Alice TV 110
1 David TV 87.5
7 Jerry TV 56
I understand basic 'partitioning over order by' however I have not used it over multiple tables with a datestamp. Kindly help me in understanding this concept. Thank you all in advance!
The query below should give you an idea.
select *
from (select c.cust_id,c.cust_name,ct.catalog_name,sum(o.unit_price * o.quantity) as total_sales,
,dense_rank() over(partition by ct.catalog_name order by sum(o.unit_price * o.quantity) desc) as rnk
from customers c
join orders o on o.cust_id = c.cust_id
join catalog ct on ct.catalog_id = o.catalog_id
--last 30 days filter
where o.order_date >= date_add(day,-30,cast(getdate() as date)) and o.order_date < cast(getdate() as date)
group by c.cust_id,c.cust_name,ct.catalog_name
) t
where rnk <= 3

Specific Ordering in SQL

I have a SQL Server 2008 database. In this database, I have a result set that looks like the following:
ID Name Department LastOrderDate
-- ---- ---------- -------------
1 Golf Balls Sports 01/01/2015
2 Compact Disc Electronics 02/01/2015
3 Tires Automotive 01/15/2015
4 T-Shirt Clothing 01/10/2015
5 DVD Electronics 01/07/2015
6 Tennis Balls Sports 01/09/2015
7 Sweatshirt Clothing 01/04/2015
...
For some reason, my users want to get the results ordered by department, then last order date. However, not by department name. Instead, the departments will be in a specific order. For example, they want to see the results ordered by Electronics, Automotive, Sports, then Clothing. To throw another kink in works, I cannot update the table schema.
Is there a way to do this with a SQL Query? If so, how? Currently, I'm stuck at
SELECT *
FROM
vOrders o
ORDER BY
o.LastOrderDate
Thank you!
You can use case expression ;
order by case when department = 'Electronics' then 1
when department = 'Automotive' then 2
when department = 'Sports' then 3
when department = 'Clothing' then 4
else 5 end
create a table for the departments that has the name (or better id) of the department and the display order. then join to that table and order by the display order column.
alternatively you can do a order by case:
ORDER BY CASE WHEN Department = 'Electronics' THEN 1
WHEN Department = 'Automotive' THEN 2
...
END
(that is not recommended for larger tables)
Here solution with CTE
with c (iOrder, dept)
as (
Select 1, 'Electronics'
Union
Select 2, 'Automotive'
Union
Select 3, 'Sports'
Union
Select 4, 'Clothing'
)
Select * from c
SELECT o.*
FROM
vOrders o join c
on c.dept = o.Department
ORDER BY
c.iOrder

How to produce detail, not summary, report sorted by count(*)?

Oracle 11g:
I want results to list by highest count, then ch_id. When I use group by to get the count then I loose the granularity of the detail. Is there an analytic function I could use?
SALES
ch_id desc customer
=========================
ANAR Anari BOB
SWIS Swiss JOE
SWIS Swiss AMY
BRUN Brunost SAM
BRUN Brunost ANN
BRUN Brunost ROB
Desired Results
count ch_id customer
===========================================
3 BRUN ANN
3 BRUN ROB
3 BRUN SAM
2 SWIS AMY
2 SWIS JOE
1 ANAR BOB
Use the analytic count(*):
select * from
(
select count(*) over (partition by ch_id) cnt,
ch_id, customer
from sales
)
order by cnt desc
select total, ch_id, customer
from sales s
inner join (select count(*) total, ch_id from sales group by ch_id) b
on b.ch_id = s.chi_id
order by total, ch_id
ok - the other post that happened at the same time, using partition, is the better solution for Oracle. But this one works regardless of DB.