Selecting City from Customer ID in SQL - sql

Customer have ordered from different cities. Thus we have multiple cities against same customer_id. I want to display that city against customer id which has occurred maximum number of times , in case where customer has ordered same number of orders from multiple cities that city should be selected from where he has placed last order. I have tried something like
SELECT customer_id,delivery_city,COUNT(DISTINCT delivery_city)
FROM analytics.f_order
GROUP BY customer_id,delivery_city
HAVING COUNT(DISTINCT delivery_city) > 1

WITH cte as (
SELECT customer_id,
delivery_city,
COUNT(delivery_city) as city_count,
MAX(order_date) as last_order
FROM analytics.f_order
GROUP BY customer_id, delivery_city
), ranking as (
SELECT *, row_number() over (partition by customer_id
order by city_count DESC, last_order DESC) as rn
FROM cte
)
SELECT *
FROM ranking
WHERE rn = 1

select customer_id,
delivery_city,
amount
from
(
select t.*,
rank() over (partition by customer_id order by amount asc) as rank
from(
SELECT customer_id,
delivery_city,
COUNT(DISTINCT delivery_city) as amount
FROM analytics.f_order
GROUP BY customer_id,delivery_city
) t
)
where rank = 1

Related

How to get last date on max count transaction_id by branch in sql

I would like to get last date on max count txn_id base on branch_name.
This is the data
I want the result like this
here is my script. but I get only one row.
select max(date),
account,
branch_name,
province,
district
from
(select date,
account,
branch_name,
province,
district,
RANK() OVER (ODER BY txn_no desc) rnk
from
(select count(tr.txn_id) txn_no,
tr.date,
u.account,
b.branch_name,
b.province,
b.district
from transaction tr
inner join users u
on u.user_id = tr.user_id
inner join branch b
on b.user_id = u.user_id
where 1=1
and tr.date >= to_date('01/04/2021','dd/mm/yyyy') and tr.date < to_date('30/04/2021','dd/mm/yyyy')
group by tr.date,
u.account,
b.branch_name,
b.province,
b.district
))
where rnk = 1
group by tr.date,
u.account,
b.branch_name,
b.province,
b.district
WITH
cte1 AS ( SELECT *, COUNT(*) OVER (PARTITION user, branch) cnt
FROM source_table ),
cte2 AS ( SELECT *, RANK() OVER (PARTITION BY user ORDER BY cnt DESC) rnk
FROM cte1 )
SELECT *
FROM cte2
WHERE rnk = 1
If more than one branch have the same amount of rows then all of them will be returned. If only one of them must be returned in this case then according additional criteria must be used and ORDER BY expression clause in cte2 must be accordingly expanded. If any (random) must be returned in this case then RANK() in cte2 must be replaced with ROW_NUMBER().
I would do it with SELECT TOP 1 ... instead of RANK(), something like:
SELECT date,
txn_id,
account,
branch_name,
province,
district
FROM transaction t
WHERE branch_name = (
SELECT TOP 1 branch_name
FROM (
SELECT branch_name, count(*) as cnt
FROM transaction
WHERE account = t.account
GROUP BY branch_name
ORDER BY 2 DESC
) s
AND date = (
SELECT TOP 1 date
FROM (
SELECT date, count(*) as cnt
FROM transaction
WHERE account = t.account
AND branch_name = (
SELECT TOP 1 branch_name
FROM (
SELECT branch_name, count(*) as cnt
FROM transaction
WHERE account = t.account
GROUP BY branch_name
ORDER BY 2 DESC
) s2
GROUP BY branch_name
ORDER BY 2 DESC
) s2
)
If there are multiple transactions on the last date, they all are going to be returned though.
You want the most recent transaction from the account/branch with the most transactions. If so, you can do this as:
select t.*
from (select t.*,
max(cnt) over (partition by account) as max_cnt
from (select t.*,
count(*) over (partition by account, branch_name) as cnt,
row_number() over (partition by account, branch_name order by date desc) as seqnum
from t
) t
) t
where max_cnt = cnt and seqnum = 1;
Note: If there are multiple branches that have the same count, then they are all returned. Your question does not specify how to deal with such duplicates.

how to make a request?

I have a table Tabl1 : id, name, country, year, medal.
how can I find the top 10 countries by the number of medals for each year in 1 request?
thanks:)
You haven't told us anything about your table schema or the data, so this is a guess!
Going to assume your medal column contains the qty of medals for each Id/name, so you just need to rank by the sum of medals. Something along the lines of:
select [year], country, [Rank] from (
select [year], country, Rank() over(partition by [year] order by Sum(medal) desc ) [Rank]
from Tabl1
group by [year],country
)x
where [Rank]<=10
order by [year], [Rank]
here you can get the top 10 countries in each year:
select * from
(
select country,year,count(*),row_number() over (order by count(*) desc) as rn
from table
group by country, year
) tt
where tt.rn < 11
the sub query groups the data per country and year and gives you count() of each group, but at the same time It sorts them per count(*) desc and gives the a row number per each group ( it happanes using row_number() window funcion) , so the country with the most medal in eacg year is on top and it gets row number = 1 in each group , you need top 10 , so you filter them tt.rn < 11 in the main query.
If you want 10 countries per year:
with data as (
select country, "year" as yr,
rank() over (partition by "year" order by count(*) desc) as rnk
from T
group by country, "year"
)
select yr as "year", country from data
where rnk <= 10
order by yr, rnk;
Note that if ties are possible this could return more than ten rows for any given year.

SQL show the first and last value in count

I need to write a query that show the max and the min count of order the customer order.
I tried:
(SELECT TOP 1 CustomerID, COUNT(*) AS Number_Of_Orders
FROM Orders
GROUP BY CustomerID
ORDER BY COUNT(*) ASC)
UNION ALL
(SELECT TOP 1 CustomerID, COUNT(*) AS Number_Of_Orders
FROM Orders
GROUP BY CustomerID
ORDER BY COUNT(*) DESC)
But I don't succeed to union between the output, I got the error Incorrect syntax near the keyword 'ORDER'.
How can I get that?
I'm not sure I would want to run the aggregation twice, so use window functions:
SELECT CustomerID, Number_Of_Orders
FROM (SELECT CustomerID, COUNT(*) AS Number_Of_Orders,
ROW_NUMBER() OVER (ORDER BY COUNT(*) ASC) as seqnum_asc,
ROW_NUMBER() OVER (ORDER BY COUNT(*) DESC) as seqnum_desc
FROM Orders
GROUP BY CustomerID
) c
WHERE seqnum_asc = 1 OR seqnum_desc = 1;
You can't use ORDER BY inside the queries that you want to unify with UNION, but you can do this:
SELECT * FROM
(SELECT TOP 1 CustomerID, COUNT(*) AS Number_Of_Orders
FROM Orders
GROUP BY CustomerID
ORDER BY COUNT(*) ASC) t
UNION ALL
SELECT * FROM
(SELECT TOP 1 CustomerID, COUNT(*) AS Number_Of_Orders
FROM Orders
GROUP BY CustomerID
ORDER BY COUNT(*) DESC) t
This does the trick although it is inefficient because you execute twice the same code and sort twice.
You can use window functions for this. This will give you multiple customers for min/max if there are ties (fiddle):
SELECT CustomerID
, OrderCount
, CASE WHEN OrderCount = MinOrderCount THEN 'Customer with min orders'
WHEN OrderCount = MaxOrderCount THEN 'Customer with max orders' END AS Type
FROM (
SELECT CustomerID
, COUNT(*) AS OrderCount
, MIN(COUNT(*)) OVER () AS MinOrderCount
, MAX(COUNT(*)) OVER () AS MaxOrderCount
FROM Orders
GROUP BY CustomerID
) AS x
WHERE OrderCount = MinOrderCount OR OrderCount = MaxOrderCount

prepare the monthly sales report for the customer who has the maximum sales, for the below table

prepare the monthly sales report for the customer who has the maximum sales, for the below table
This is an example of how you can retrieve in 'one' query:
the id of the customer who has the maximum sales
the sales summary of this customer
First the query that brings the customer_id and the corresponding summary of sales is like:
select customer_id, sum(sales) as sumsales from mytable group by customer_id;
To this query, a rank has to be added to the descending order of Sales summaries. This will allow to select a single record according to its rank later. So, a wrap is necessary:
select customer_id, sumsales, rank() over (order by sumsales desc) as rnk from
(select customer_id, sum(sales) as sumsales from mytable group by customer_id);
Now that the ranked entries are available, the first ranked record has to be selected:
select customer_id, sumsales from
(select customer_id, sumsales, rank() over (order by sumsales desc) as rnk from
(select customer_id, sum(sales) as sumsales from mytable group by customer_id)
)
where rnk=1;
However, this may not be the most effective way to achieve this.
EDIT:
In order to avoid a wrapping layer, just to add the rank, it is possible to add the rank foeld to the first internal query:
select customer_id, sum(sales) as sumsales, rank() over (order by sum(sales) desc) as rnk
from mytable group by customer_id;
And then, a single wrapping query is needed to select the first ranked record as:
select customer_id, sumsales from (
select customer_id, sum(sales) as sumsales, rank() over (order by sum(sales) desc) as rnk
from mytable group by customer_id
)
where rnk=1;
Reference to other similar relevant answers here.

Maximum count - PostgreSQL

I'm looking to pull the max(count(*)) of something from a table.
Effectively what i'm trying to do is pull out a customers favourite brand. So they buy 300 bars of soap a year but I'd like to know which their favourite is. So the max(count(brand_id) basically.
I was thinking of doing it like this:
SELECT
transaction.customer_id,
max(occ)
FROM
( SELECT
transaction.customer_id,
count(transaction.brand_id) as occ,
FROM
transaction
GROUP BY
transaction.customer_id,
) AS foo
GROUP BY
transaction.customer_id
Thanks in advance
you can do it like this:
with cte as (
select customer_id, brand_id, count(*) as cnt
from test1
group by customer_id, brand_id
)
select distinct on (customer_id)
customer_id, brand_id, cnt
from cte
order by customer_id, cnt desc
Keep in mind, that if there more than one brand with equal count for some customer, you'll end up with one arbitrary record. If you want to get all records, use dense_rank() function:
with cte1 as (
select customer_id, brand_id, count(*) as cnt
from test1
group by customer_id, brand_id
), cte2 as (
select
customer_id, brand_id,
dense_rank() over(partition by customer_id order by cnt desc) as rn
from cte1
)
select customer_id, brand_id
from cte2
where rn = 1
sql fiddle demo
For PostgreSQL 8.3:
select distinct on (customer_id)
customer_id, brand_id, cnt
from (
select customer_id, brand_id, count(*) as cnt
from test1
group by customer_id, brand_id
) as c
order by customer_id, cnt desc;
sql fiddle demo
or like this
with cte as (
SELECT
transaction.customer_id,
count(transaction.brand_id) as occ,
FROM
transaction
GROUP BY
transaction.customer_id
)
select max(occ) from cte